From 82ad65a3a4d363a45015ba404a9e1aaf531e68ab Mon Sep 17 00:00:00 2001 From: alexion Date: Wed, 16 Sep 2026 15:51:43 -0400 Subject: [PATCH] build(rust): vendor rnix parser crate --- Cargo.lock | 52 + third_party/BUILD | 7 +- third_party/crates/BUILD.bazel | 12 + .../crates/countme-3.0.1/.cargo-checksum.json | 1 + .../crates/countme-3.0.1/.cargo_vcs_info.json | 6 + .../countme-3.0.1/.vscode/settings.json | 3 + third_party/crates/countme-3.0.1/BUILD.bazel | 110 + third_party/crates/countme-3.0.1/Cargo.lock | 168 + third_party/crates/countme-3.0.1/Cargo.toml | 48 + .../crates/countme-3.0.1/Cargo.toml.orig | 35 + .../crates/countme-3.0.1/LICENSE-APACHE | 201 + third_party/crates/countme-3.0.1/LICENSE-MIT | 23 + third_party/crates/countme-3.0.1/README.md | 21 + .../crates/countme-3.0.1/examples/bench.rs | 69 + .../examples/bench_single_thread.rs | 77 + .../countme-3.0.1/examples/print_at_exit.rs | 11 + third_party/crates/countme-3.0.1/src/imp.rs | 175 + third_party/crates/countme-3.0.1/src/lib.rs | 193 + third_party/crates/crates.bzl | 30 + .../hashbrown-0.14.5/.cargo-checksum.json | 1 + .../hashbrown-0.14.5/.cargo_vcs_info.json | 6 + .../crates/hashbrown-0.14.5/BUILD.bazel | 113 + .../crates/hashbrown-0.14.5/CHANGELOG.md | 532 + .../crates/hashbrown-0.14.5/Cargo.toml | 137 + .../crates/hashbrown-0.14.5/Cargo.toml.orig | 71 + .../crates/hashbrown-0.14.5/LICENSE-APACHE | 201 + .../crates/hashbrown-0.14.5/LICENSE-MIT | 25 + third_party/crates/hashbrown-0.14.5/README.md | 125 + .../crates/hashbrown-0.14.5/benches/bench.rs | 331 + .../benches/insert_unique_unchecked.rs | 32 + .../crates/hashbrown-0.14.5/clippy.toml | 1 + .../src/external_trait_impls/mod.rs | 6 + .../src/external_trait_impls/rayon/helpers.rs | 27 + .../src/external_trait_impls/rayon/map.rs | 721 + .../src/external_trait_impls/rayon/mod.rs | 5 + .../src/external_trait_impls/rayon/raw.rs | 230 + .../src/external_trait_impls/rayon/set.rs | 659 + .../src/external_trait_impls/rayon/table.rs | 252 + .../src/external_trait_impls/rkyv/hash_map.rs | 125 + .../src/external_trait_impls/rkyv/hash_set.rs | 123 + .../src/external_trait_impls/rkyv/mod.rs | 2 + .../src/external_trait_impls/serde.rs | 220 + .../crates/hashbrown-0.14.5/src/lib.rs | 188 + .../crates/hashbrown-0.14.5/src/macros.rs | 70 + .../crates/hashbrown-0.14.5/src/map.rs | 8960 ++++++ .../crates/hashbrown-0.14.5/src/raw/alloc.rs | 86 + .../hashbrown-0.14.5/src/raw/bitmask.rs | 133 + .../hashbrown-0.14.5/src/raw/generic.rs | 157 + .../crates/hashbrown-0.14.5/src/raw/mod.rs | 4817 +++ .../crates/hashbrown-0.14.5/src/raw/neon.rs | 124 + .../crates/hashbrown-0.14.5/src/raw/sse2.rs | 149 + .../hashbrown-0.14.5/src/rustc_entry.rs | 630 + .../crates/hashbrown-0.14.5/src/scopeguard.rs | 72 + .../crates/hashbrown-0.14.5/src/set.rs | 2970 ++ .../crates/hashbrown-0.14.5/src/table.rs | 2070 ++ .../tests/equivalent_trait.rs | 53 + .../crates/hashbrown-0.14.5/tests/hasher.rs | 65 + .../crates/hashbrown-0.14.5/tests/raw.rs | 11 + .../crates/hashbrown-0.14.5/tests/rayon.rs | 535 + .../crates/hashbrown-0.14.5/tests/serde.rs | 65 + .../crates/hashbrown-0.14.5/tests/set.rs | 34 + .../crates/rnix-0.14.0/.cargo-checksum.json | 1 + .../crates/rnix-0.14.0/.cargo_vcs_info.json | 7 + .../.github/ISSUE_TEMPLATE/bug_report.md | 36 + .../.github/ISSUE_TEMPLATE/feature_request.md | 29 + .../.github/ISSUE_TEMPLATE/question.md | 7 + .../.github/PULL_REQUEST_TEMPLATE.md | 25 + .../crates/rnix-0.14.0/.github/dependabot.yml | 6 + .../rnix-0.14.0/.github/workflows/ci.yml | 64 + third_party/crates/rnix-0.14.0/BUILD.bazel | 113 + third_party/crates/rnix-0.14.0/CHANGELOG.md | 190 + third_party/crates/rnix-0.14.0/Cargo.lock | 660 + third_party/crates/rnix-0.14.0/Cargo.toml | 68 + .../crates/rnix-0.14.0/Cargo.toml.orig | 20 + third_party/crates/rnix-0.14.0/LICENSE | 21 + third_party/crates/rnix-0.14.0/MIGRATING.md | 104 + third_party/crates/rnix-0.14.0/README.md | 88 + .../rnix-0.14.0/benches/all-packages.nix | 24853 ++++++++++++++++ .../rnix-0.14.0/benches/all-packages.rs | 15 + third_party/crates/rnix-0.14.0/default.nix | 9 + .../crates/rnix-0.14.0/examples/dump-ast.rs | 24 + .../rnix-0.14.0/examples/error-report.rs | 67 + .../crates/rnix-0.14.0/examples/from-stdin.rs | 13 + .../crates/rnix-0.14.0/examples/list-fns.rs | 95 + .../crates/rnix-0.14.0/examples/preserve.rs | 19 + .../rnix-0.14.0/examples/test-nixpkgs.rs | 48 + third_party/crates/rnix-0.14.0/flake.lock | 116 + third_party/crates/rnix-0.14.0/flake.nix | 85 + third_party/crates/rnix-0.14.0/rustfmt.toml | 1 + third_party/crates/rnix-0.14.0/shell.nix | 9 + third_party/crates/rnix-0.14.0/src/ast.rs | 73 + .../crates/rnix-0.14.0/src/ast/expr_ext.rs | 29 + .../crates/rnix-0.14.0/src/ast/interpol.rs | 5 + .../crates/rnix-0.14.0/src/ast/nodes.rs | 464 + .../crates/rnix-0.14.0/src/ast/operators.rs | 71 + .../crates/rnix-0.14.0/src/ast/path_util.rs | 204 + .../crates/rnix-0.14.0/src/ast/str_util.rs | 363 + .../crates/rnix-0.14.0/src/ast/tokens.rs | 174 + third_party/crates/rnix-0.14.0/src/kinds.rs | 285 + third_party/crates/rnix-0.14.0/src/lib.rs | 111 + third_party/crates/rnix-0.14.0/src/macros.rs | 52 + third_party/crates/rnix-0.14.0/src/parser.rs | 834 + third_party/crates/rnix-0.14.0/src/tests.rs | 127 + .../crates/rnix-0.14.0/src/token_set.rs | 86 + .../crates/rnix-0.14.0/src/tokenizer.rs | 566 + .../dollar_ident_attrpath_issue174.expect | 21 + .../error/dollar_ident_attrpath_issue174.nix | 1 + .../test_data/parser/error/error.expect | 110 + .../test_data/parser/error/error.nix | 12 + .../test_data/parser/error/extra_comma.expect | 9 + .../test_data/parser/error/extra_comma.nix | 2 + .../parser/error/formals_double_bind.expect | 20 + .../parser/error/formals_double_bind.nix | 2 + .../parser/error/inherit_from_late.expect | 25 + .../parser/error/inherit_from_late.nix | 1 + .../parser/error/inherit_incomplete.expect | 11 + .../parser/error/inherit_incomplete.nix | 2 + .../parser/error/path_bare_tilde.expect | 5 + .../parser/error/path_bare_tilde.nix | 1 + .../parser/error/path_double_slash.expect | 5 + .../parser/error/path_double_slash.nix | 1 + .../error/path_interp_no_separator.expect | 10 + .../parser/error/path_interp_no_separator.nix | 1 + .../error/path_interp_trailing_slash.expect | 12 + .../error/path_interp_trailing_slash.nix | 1 + .../parser/error/path_multiple_errors.expect | 59 + .../parser/error/path_multiple_errors.nix | 7 + .../parser/error/path_store_interp.expect | 17 + .../parser/error/path_store_interp.nix | 1 + .../test_data/parser/error/path_tilde.expect | 5 + .../test_data/parser/error/path_tilde.nix | 1 + .../parser/error/path_tilde_slash.expect | 5 + .../parser/error/path_tilde_slash.nix | 1 + .../parser/error/path_trailing_slash.expect | 5 + .../parser/error/path_trailing_slash.nix | 1 + .../parser/error/select_both_errors.expect | 9 + .../parser/error/select_both_errors.nix | 1 + .../parser/error/ws_belongs_to_root.expect | 23 + .../parser/error/ws_belongs_to_root.nix | 6 + .../parser/error/ws_belongs_to_root2.expect | 10 + .../parser/error/ws_belongs_to_root2.nix | 2 + .../test_data/parser/success/apply.expect | 18 + .../test_data/parser/success/apply.nix | 1 + .../test_data/parser/success/assert.expect | 16 + .../test_data/parser/success/assert.nix | 1 + .../parser/success/attrpath_ident.expect | 19 + .../parser/success/attrpath_ident.nix | 1 + .../test_data/parser/success/attrset.expect | 28 + .../test_data/parser/success/attrset.nix | 4 + .../parser/success/attrset_dynamic.expect | 43 + .../parser/success/attrset_dynamic.nix | 4 + .../parser/success/attrset_empty.expect | 5 + .../parser/success/attrset_empty.nix | 1 + .../parser/success/attrset_rec.expect | 14 + .../test_data/parser/success/attrset_rec.nix | 1 + .../parser/success/bool_arith_ops.expect | 32 + .../parser/success/bool_arith_ops.nix | 1 + .../test_data/parser/success/bool_ops.expect | 23 + .../test_data/parser/success/bool_ops.nix | 1 + .../parser/success/bool_ops_eq.expect | 16 + .../test_data/parser/success/bool_ops_eq.nix | 1 + .../parser/success/cur_pos-as-arg.expect | 30 + .../parser/success/cur_pos-as-arg.nix | 1 + .../parser/success/cur_pos-as-ident.expect | 22 + .../parser/success/cur_pos-as-ident.nix | 1 + .../parser/success/cur_pos-lambda.expect | 10 + .../parser/success/cur_pos-lambda.nix | 1 + .../parser/success/cur_pos-no-shadow.expect | 22 + .../parser/success/cur_pos-no-shadow.nix | 1 + .../success/cur_pos-pattern-bind.expect | 17 + .../parser/success/cur_pos-pattern-bind.nix | 1 + .../cur_pos-pattern-field-default.expect | 20 + .../success/cur_pos-pattern-field-default.nix | 1 + .../success/cur_pos-pattern-field.expect | 18 + .../parser/success/cur_pos-pattern-field.nix | 1 + .../test_data/parser/success/cur_pos.expect | 4 + .../test_data/parser/success/cur_pos.nix | 1 + .../test_data/parser/success/docs.expect | 85 + .../test_data/parser/success/docs.nix | 14 + .../parser/success/has_attr_prec.expect | 15 + .../parser/success/has_attr_prec.nix | 1 + .../parser/success/if_elseif_else.expect | 30 + .../parser/success/if_elseif_else.nix | 1 + .../parser/success/import_nixpkgs.expect | 11 + .../parser/success/import_nixpkgs.nix | 1 + .../test_data/parser/success/inherit.expect | 102 + .../test_data/parser/success/inherit.nix | 8 + .../parser/success/inherit_dynamic.expect | 77 + .../parser/success/inherit_dynamic.nix | 1 + .../parser/success/interpolation.expect | 107 + .../parser/success/interpolation.nix | 18 + .../parser/success/lambda_is_not_uri.expect | 9 + .../parser/success/lambda_is_not_uri.nix | 1 + .../parser/success/lambda_list.expect | 14 + .../test_data/parser/success/lambda_list.nix | 1 + .../parser/success/lambda_nested.expect | 22 + .../parser/success/lambda_nested.nix | 1 + .../test_data/parser/success/let.expect | 20 + .../test_data/parser/success/let.nix | 1 + .../parser/success/let_legacy.expect | 22 + .../test_data/parser/success/let_legacy.nix | 1 + .../test_data/parser/success/list.expect | 18 + .../test_data/parser/success/list.nix | 1 + .../parser/success/list_concat.expect | 21 + .../test_data/parser/success/list_concat.nix | 1 + .../test_data/parser/success/math.expect | 37 + .../test_data/parser/success/math.nix | 1 + .../test_data/parser/success/math2.expect | 22 + .../test_data/parser/success/math2.nix | 1 + .../parser/success/math_no_ws.expect | 17 + .../test_data/parser/success/math_no_ws.nix | 1 + .../test_data/parser/success/merge.expect | 26 + .../test_data/parser/success/merge.nix | 1 + .../test_data/parser/success/multiple.expect | 24 + .../test_data/parser/success/multiple.nix | 1 + .../parser/success/number_list.expect | 15 + .../test_data/parser/success/number_list.nix | 1 + .../success/operators_right_assoc.expect | 84 + .../parser/success/operators_right_assoc.nix | 6 + .../parser/success/or-as-ident.expect | 18 + .../test_data/parser/success/or-as-ident.nix | 2 + .../parser/success/or_in_attr.expect | 43 + .../test_data/parser/success/or_in_attr.nix | 4 + .../test_data/parser/success/path.expect | 50 + .../test_data/parser/success/path.nix | 6 + .../success/path_abs_interp_start.expect | 9 + .../parser/success/path_abs_interp_start.nix | 1 + .../parser/success/path_complex_mix.expect | 142 + .../parser/success/path_complex_mix.nix | 17 + .../parser/success/path_interp.expect | 82 + .../test_data/parser/success/path_interp.nix | 4 + .../success/path_interp_no_prefix.expect | 9 + .../parser/success/path_interp_no_prefix.nix | 1 + .../parser/success/path_no_newline.expect | 9 + .../parser/success/path_no_newline.nix | 2 + .../parser/success/pattern_bind_left.expect | 21 + .../parser/success/pattern_bind_left.nix | 1 + .../parser/success/pattern_bind_right.expect | 16 + .../parser/success/pattern_bind_right.nix | 1 + .../parser/success/pattern_default.expect | 27 + .../parser/success/pattern_default.nix | 1 + .../success/pattern_default_attrset.expect | 16 + .../success/pattern_default_attrset.nix | 1 + .../success/pattern_default_ellipsis.expect | 30 + .../success/pattern_default_ellipsis.nix | 1 + .../parser/success/pattern_ellipsis.expect | 13 + .../parser/success/pattern_ellipsis.nix | 1 + .../success/pattern_trailing_comma.expect | 13 + .../parser/success/pattern_trailing_comma.nix | 1 + .../test_data/parser/success/pipe_left.expect | 15 + .../test_data/parser/success/pipe_left.nix | 1 + .../parser/success/pipe_left_assoc.expect | 21 + .../parser/success/pipe_left_assoc.nix | 1 + .../parser/success/pipe_left_math.expect | 21 + .../parser/success/pipe_left_math.nix | 1 + .../parser/success/pipe_mixed.expect | 21 + .../test_data/parser/success/pipe_mixed.nix | 1 + .../parser/success/pipe_mixed_math.expect | 27 + .../parser/success/pipe_mixed_math.nix | 1 + .../parser/success/pipe_right.expect | 15 + .../test_data/parser/success/pipe_right.nix | 1 + .../parser/success/pipe_right_assoc.expect | 21 + .../parser/success/pipe_right_assoc.nix | 1 + .../parser/success/pipe_right_math.expect | 21 + .../parser/success/pipe_right_math.nix | 1 + .../parser/success/select_default.expect | 23 + .../parser/success/select_default.nix | 1 + .../parser/success/select_ident.expect | 12 + .../test_data/parser/success/select_ident.nix | 1 + .../success/select_string_dynamic.expect | 26 + .../parser/success/select_string_dynamic.nix | 1 + .../test_data/parser/success/string.expect | 43 + .../test_data/parser/success/string.nix | 8 + .../parser/success/string_complex_url.expect | 17 + .../parser/success/string_complex_url.nix | 4 + .../success/string_escape_issue175.expect | 6 + .../parser/success/string_escape_issue175.nix | 3 + .../parser/success/string_interp_ident.expect | 18 + .../parser/success/string_interp_ident.nix | 1 + .../success/string_interp_nested.expect | 18 + .../parser/success/string_interp_nested.nix | 1 + .../success/string_interp_select.expect | 36 + .../parser/success/string_interp_select.nix | 1 + .../test_data/parser/success/trivia.expect | 84 + .../test_data/parser/success/trivia.nix | 9 + .../parser/success/uri_various.expect | 96 + .../test_data/parser/success/uri_various.nix | 12 + .../parser/success/with-import-let-in.expect | 93 + .../parser/success/with-import-let-in.nix | 12 + .../test_data/parser/success/with.expect | 11 + .../test_data/parser/success/with.nix | 1 + .../error/path_double_slash_middle.expect | 1 + .../error/path_double_slash_middle.nix | 1 + .../error/path_home_double_slash.expect | 1 + .../error/path_home_double_slash.nix | 1 + .../error/path_interp_trailing_slash.expect | 5 + .../error/path_interp_trailing_slash.nix | 1 + .../tokenizer/error/path_tilde.expect | 1 + .../test_data/tokenizer/error/path_tilde.nix | 1 + .../tokenizer/error/path_tilde_slash.expect | 1 + .../tokenizer/error/path_tilde_slash.nix | 1 + .../error/path_trailing_slash.expect | 1 + .../tokenizer/error/path_trailing_slash.nix | 1 + .../success/comment_interspersed.expect | 16 + .../success/comment_interspersed.nix | 2 + .../success/comment_multiline.expect | 1 + .../tokenizer/success/comment_multiline.nix | 1 + .../success/comment_multiline2.expect | 1 + .../tokenizer/success/comment_multiline2.nix | 1 + .../test_data/tokenizer/success/float.expect | 1 + .../test_data/tokenizer/success/float.nix | 1 + .../success/float_no_leading_part.expect | 1 + .../success/float_no_leading_part.nix | 1 + .../success/float_no_trailing_part.expect | 1 + .../success/float_no_trailing_part.nix | 1 + .../success/float_scientific_lower.expect | 1 + .../success/float_scientific_lower.nix | 1 + .../success/float_scientific_neg.expect | 1 + .../success/float_scientific_neg.nix | 1 + .../success/float_scientific_pos.expect | 1 + .../success/float_scientific_pos.nix | 1 + .../success/float_scientific_upper.expect | 1 + .../success/float_scientific_upper.nix | 1 + .../test_data/tokenizer/success/int.expect | 1 + .../test_data/tokenizer/success/int.nix | 1 + .../test_data/tokenizer/success/lambda.expect | 11 + .../test_data/tokenizer/success/lambda.nix | 1 + .../success/lambda_arg_underscore.expect | 3 + .../success/lambda_arg_underscore.nix | 1 + .../success/leading_zero_edge_case_01.expect | 3 + .../success/leading_zero_edge_case_01.nix | 1 + .../success/leading_zero_edge_case_02.expect | 2 + .../success/leading_zero_edge_case_02.nix | 1 + .../success/leading_zero_numbers.expect | 4 + .../success/leading_zero_numbers.nix | 1 + .../test_data/tokenizer/success/let.expect | 12 + .../test_data/tokenizer/success/let.nix | 1 + .../test_data/tokenizer/success/list.expect | 11 + .../test_data/tokenizer/success/list.nix | 1 + .../tokenizer/success/list_concat.expect | 15 + .../tokenizer/success/list_concat.nix | 1 + .../test_data/tokenizer/success/math.expect | 23 + .../test_data/tokenizer/success/math.nix | 1 + .../success/math_div_isnt_path.expect | 4 + .../tokenizer/success/math_div_isnt_path.nix | 1 + .../tokenizer/success/math_no_ws.expect | 8 + .../tokenizer/success/math_no_ws.nix | 1 + .../tokenizer/success/op_geq_isnt_path.expect | 3 + .../tokenizer/success/op_geq_isnt_path.nix | 1 + .../tokenizer/success/op_update.expect | 3 + .../test_data/tokenizer/success/op_update.nix | 1 + .../success/path_abs_interp_start.expect | 4 + .../success/path_abs_interp_start.nix | 1 + .../path_abs_interp_start_suffix.expect | 5 + .../success/path_abs_interp_start_suffix.nix | 1 + .../success/path_abs_nix_store.expect | 1 + .../tokenizer/success/path_abs_nix_store.nix | 1 + .../tokenizer/success/path_absolute.expect | 1 + .../tokenizer/success/path_absolute.nix | 1 + .../tokenizer/success/path_home.expect | 1 + .../test_data/tokenizer/success/path_home.nix | 1 + .../tokenizer/success/path_home_hidden.expect | 1 + .../tokenizer/success/path_home_hidden.nix | 1 + .../tokenizer/success/path_interp.expect | 4 + .../tokenizer/success/path_interp.nix | 1 + .../success/path_interp_apply.expect | 6 + .../tokenizer/success/path_interp_apply.nix | 1 + .../success/path_interp_multiple.expect | 7 + .../success/path_interp_multiple.nix | 1 + .../success/path_interp_multiple2.expect | 8 + .../success/path_interp_multiple2.nix | 1 + .../success/path_interp_then_plain.expect | 5 + .../success/path_interp_then_plain.nix | 1 + .../tokenizer/success/path_isnt_math.expect | 1 + .../tokenizer/success/path_isnt_math.nix | 1 + .../tokenizer/success/path_no_newline.expect | 5 + .../tokenizer/success/path_no_newline.nix | 2 + .../success/path_operators_mix.expect | 9 + .../tokenizer/success/path_operators_mix.nix | 1 + .../tokenizer/success/path_relative.expect | 1 + .../tokenizer/success/path_relative.nix | 1 + .../success/path_relative_complex.expect | 1 + .../success/path_relative_complex.nix | 1 + .../success/path_relative_prefix.expect | 1 + .../success/path_relative_prefix.nix | 1 + .../success/path_search_complex.expect | 1 + .../tokenizer/success/path_search_complex.nix | 1 + .../success/path_search_with_dash.expect | 1 + .../success/path_search_with_dash.nix | 1 + .../tokenizer/success/path_store.expect | 1 + .../tokenizer/success/path_store.nix | 1 + .../tokenizer/success/path_underscore.expect | 1 + .../tokenizer/success/path_underscore.nix | 1 + .../success/path_with_numbers.expect | 1 + .../tokenizer/success/path_with_numbers.nix | 1 + .../tokenizer/success/path_with_plus.expect | 1 + .../tokenizer/success/path_with_plus.nix | 1 + .../tokenizer/success/patterns.expect | 21 + .../test_data/tokenizer/success/patterns.nix | 1 + .../tokenizer/success/select_dynamic.expect | 7 + .../tokenizer/success/select_dynamic.nix | 1 + .../test_data/tokenizer/success/string.expect | 3 + .../test_data/tokenizer/success/string.nix | 1 + .../success/string_dollar_escape.expect | 3 + .../success/string_dollar_escape.nix | 1 + .../tokenizer/success/string_escape.expect | 3 + .../tokenizer/success/string_escape.nix | 1 + .../tokenizer/success/string_interp.expect | 9 + .../tokenizer/success/string_interp.nix | 1 + .../string_interp_dollar_escape.expect | 6 + .../success/string_interp_dollar_escape.nix | 1 + .../success/string_interp_nested.expect | 9 + .../success/string_interp_nested.nix | 1 + .../success/string_interp_select.expect | 22 + .../success/string_interp_select.nix | 1 + .../tokenizer/success/string_isnt_path.expect | 6 + .../tokenizer/success/string_isnt_path.nix | 1 + .../tokenizer/success/string_multiline.expect | 11 + .../tokenizer/success/string_multiline.nix | 9 + .../string_multiline_dollar_escape.expect | 3 + .../string_multiline_dollar_escape.nix | 1 + .../string_multiline_interp_escape.expect | 6 + .../string_multiline_interp_escape.nix | 1 + .../test_data/tokenizer/success/uri.expect | 1 + .../test_data/tokenizer/success/uri.nix | 1 + .../tokenizer/success/uri_git_ssh.expect | 1 + .../tokenizer/success/uri_git_ssh.nix | 1 + .../tokenizer/success/uri_https.expect | 1 + .../test_data/tokenizer/success/uri_https.nix | 1 + .../success/uri_with_underscore.expect | 1 + .../tokenizer/success/uri_with_underscore.nix | 1 + .../test_data/tokenizer/success/with.expect | 6 + .../test_data/tokenizer/success/with.nix | 1 + .../crates/rowan-0.16.1/.cargo-checksum.json | 1 + .../crates/rowan-0.16.1/.cargo_vcs_info.json | 6 + third_party/crates/rowan-0.16.1/BUILD.bazel | 116 + third_party/crates/rowan-0.16.1/Cargo.lock | 150 + third_party/crates/rowan-0.16.1/Cargo.toml | 75 + .../crates/rowan-0.16.1/Cargo.toml.orig | 29 + .../crates/rowan-0.16.1/LICENSE-APACHE | 201 + third_party/crates/rowan-0.16.1/LICENSE-MIT | 23 + third_party/crates/rowan-0.16.1/README.md | 22 + .../crates/rowan-0.16.1/examples/math.rs | 152 + .../rowan-0.16.1/examples/s_expressions.rs | 425 + third_party/crates/rowan-0.16.1/src/api.rs | 554 + third_party/crates/rowan-0.16.1/src/arc.rs | 458 + third_party/crates/rowan-0.16.1/src/ast.rs | 287 + .../crates/rowan-0.16.1/src/cow_mut.rs | 30 + third_party/crates/rowan-0.16.1/src/cursor.rs | 1592 + third_party/crates/rowan-0.16.1/src/green.rs | 42 + .../crates/rowan-0.16.1/src/green/builder.rs | 131 + .../crates/rowan-0.16.1/src/green/element.rs | 89 + .../crates/rowan-0.16.1/src/green/node.rs | 359 + .../rowan-0.16.1/src/green/node_cache.rs | 157 + .../crates/rowan-0.16.1/src/green/token.rs | 143 + third_party/crates/rowan-0.16.1/src/lib.rs | 41 + .../crates/rowan-0.16.1/src/serde_impls.rs | 66 + third_party/crates/rowan-0.16.1/src/sll.rs | 128 + .../crates/rowan-0.16.1/src/syntax_text.rs | 311 + .../crates/rowan-0.16.1/src/utility_types.rs | 180 + third_party/crates/rowan-0.16.1/tests/tidy.rs | 46 + .../rustc-hash-1.1.0/.cargo-checksum.json | 1 + .../rustc-hash-1.1.0/.cargo_vcs_info.json | 5 + .../crates/rustc-hash-1.1.0/BUILD.bazel | 114 + .../rustc-hash-1.1.0/CODE_OF_CONDUCT.md | 40 + .../crates/rustc-hash-1.1.0/Cargo.toml | 25 + .../crates/rustc-hash-1.1.0/Cargo.toml.orig | 13 + .../crates/rustc-hash-1.1.0/LICENSE-APACHE | 201 + .../crates/rustc-hash-1.1.0/LICENSE-MIT | 23 + third_party/crates/rustc-hash-1.1.0/README.md | 38 + .../crates/rustc-hash-1.1.0/src/lib.rs | 148 + .../text-size-1.1.1/.cargo-checksum.json | 1 + .../text-size-1.1.1/.cargo_vcs_info.json | 6 + .../text-size-1.1.1/.github/workflows/ci.yaml | 54 + .../crates/text-size-1.1.1/BUILD.bazel | 110 + .../crates/text-size-1.1.1/CHANGELOG.md | 26 + third_party/crates/text-size-1.1.1/Cargo.toml | 40 + .../crates/text-size-1.1.1/Cargo.toml.orig | 25 + .../crates/text-size-1.1.1/LICENSE-APACHE | 201 + .../crates/text-size-1.1.1/LICENSE-MIT | 23 + third_party/crates/text-size-1.1.1/README.md | 27 + third_party/crates/text-size-1.1.1/bors.toml | 6 + third_party/crates/text-size-1.1.1/src/lib.rs | 32 + .../crates/text-size-1.1.1/src/range.rs | 456 + .../crates/text-size-1.1.1/src/serde_impls.rs | 48 + .../crates/text-size-1.1.1/src/size.rs | 173 + .../crates/text-size-1.1.1/src/traits.rs | 36 + .../text-size-1.1.1/tests/auto_traits.rs | 18 + .../text-size-1.1.1/tests/constructors.rs | 24 + .../crates/text-size-1.1.1/tests/indexing.rs | 8 + .../crates/text-size-1.1.1/tests/main.rs | 76 + .../crates/text-size-1.1.1/tests/serde.rs | 79 + 492 files changed, 67785 insertions(+), 1 deletion(-) create mode 100644 third_party/crates/countme-3.0.1/.cargo-checksum.json create mode 100644 third_party/crates/countme-3.0.1/.cargo_vcs_info.json create mode 100644 third_party/crates/countme-3.0.1/.vscode/settings.json create mode 100644 third_party/crates/countme-3.0.1/BUILD.bazel create mode 100644 third_party/crates/countme-3.0.1/Cargo.lock create mode 100644 third_party/crates/countme-3.0.1/Cargo.toml create mode 100644 third_party/crates/countme-3.0.1/Cargo.toml.orig create mode 100644 third_party/crates/countme-3.0.1/LICENSE-APACHE create mode 100644 third_party/crates/countme-3.0.1/LICENSE-MIT create mode 100644 third_party/crates/countme-3.0.1/README.md create mode 100644 third_party/crates/countme-3.0.1/examples/bench.rs create mode 100644 third_party/crates/countme-3.0.1/examples/bench_single_thread.rs create mode 100644 third_party/crates/countme-3.0.1/examples/print_at_exit.rs create mode 100644 third_party/crates/countme-3.0.1/src/imp.rs create mode 100644 third_party/crates/countme-3.0.1/src/lib.rs create mode 100644 third_party/crates/hashbrown-0.14.5/.cargo-checksum.json create mode 100644 third_party/crates/hashbrown-0.14.5/.cargo_vcs_info.json create mode 100644 third_party/crates/hashbrown-0.14.5/BUILD.bazel create mode 100644 third_party/crates/hashbrown-0.14.5/CHANGELOG.md create mode 100644 third_party/crates/hashbrown-0.14.5/Cargo.toml create mode 100644 third_party/crates/hashbrown-0.14.5/Cargo.toml.orig create mode 100644 third_party/crates/hashbrown-0.14.5/LICENSE-APACHE create mode 100644 third_party/crates/hashbrown-0.14.5/LICENSE-MIT create mode 100644 third_party/crates/hashbrown-0.14.5/README.md create mode 100644 third_party/crates/hashbrown-0.14.5/benches/bench.rs create mode 100644 third_party/crates/hashbrown-0.14.5/benches/insert_unique_unchecked.rs create mode 100644 third_party/crates/hashbrown-0.14.5/clippy.toml create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/mod.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/external_trait_impls/serde.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/lib.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/macros.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/map.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/raw/alloc.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/raw/bitmask.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/raw/generic.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/raw/mod.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/raw/neon.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/raw/sse2.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/rustc_entry.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/scopeguard.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/set.rs create mode 100644 third_party/crates/hashbrown-0.14.5/src/table.rs create mode 100644 third_party/crates/hashbrown-0.14.5/tests/equivalent_trait.rs create mode 100644 third_party/crates/hashbrown-0.14.5/tests/hasher.rs create mode 100644 third_party/crates/hashbrown-0.14.5/tests/raw.rs create mode 100644 third_party/crates/hashbrown-0.14.5/tests/rayon.rs create mode 100644 third_party/crates/hashbrown-0.14.5/tests/serde.rs create mode 100644 third_party/crates/hashbrown-0.14.5/tests/set.rs create mode 100644 third_party/crates/rnix-0.14.0/.cargo-checksum.json create mode 100644 third_party/crates/rnix-0.14.0/.cargo_vcs_info.json create mode 100644 third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/question.md create mode 100644 third_party/crates/rnix-0.14.0/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 third_party/crates/rnix-0.14.0/.github/dependabot.yml create mode 100644 third_party/crates/rnix-0.14.0/.github/workflows/ci.yml create mode 100644 third_party/crates/rnix-0.14.0/BUILD.bazel create mode 100644 third_party/crates/rnix-0.14.0/CHANGELOG.md create mode 100644 third_party/crates/rnix-0.14.0/Cargo.lock create mode 100644 third_party/crates/rnix-0.14.0/Cargo.toml create mode 100644 third_party/crates/rnix-0.14.0/Cargo.toml.orig create mode 100644 third_party/crates/rnix-0.14.0/LICENSE create mode 100644 third_party/crates/rnix-0.14.0/MIGRATING.md create mode 100644 third_party/crates/rnix-0.14.0/README.md create mode 100644 third_party/crates/rnix-0.14.0/benches/all-packages.nix create mode 100644 third_party/crates/rnix-0.14.0/benches/all-packages.rs create mode 100644 third_party/crates/rnix-0.14.0/default.nix create mode 100644 third_party/crates/rnix-0.14.0/examples/dump-ast.rs create mode 100644 third_party/crates/rnix-0.14.0/examples/error-report.rs create mode 100644 third_party/crates/rnix-0.14.0/examples/from-stdin.rs create mode 100644 third_party/crates/rnix-0.14.0/examples/list-fns.rs create mode 100644 third_party/crates/rnix-0.14.0/examples/preserve.rs create mode 100644 third_party/crates/rnix-0.14.0/examples/test-nixpkgs.rs create mode 100644 third_party/crates/rnix-0.14.0/flake.lock create mode 100644 third_party/crates/rnix-0.14.0/flake.nix create mode 100644 third_party/crates/rnix-0.14.0/rustfmt.toml create mode 100644 third_party/crates/rnix-0.14.0/shell.nix create mode 100644 third_party/crates/rnix-0.14.0/src/ast.rs create mode 100644 third_party/crates/rnix-0.14.0/src/ast/expr_ext.rs create mode 100644 third_party/crates/rnix-0.14.0/src/ast/interpol.rs create mode 100644 third_party/crates/rnix-0.14.0/src/ast/nodes.rs create mode 100644 third_party/crates/rnix-0.14.0/src/ast/operators.rs create mode 100644 third_party/crates/rnix-0.14.0/src/ast/path_util.rs create mode 100644 third_party/crates/rnix-0.14.0/src/ast/str_util.rs create mode 100644 third_party/crates/rnix-0.14.0/src/ast/tokens.rs create mode 100644 third_party/crates/rnix-0.14.0/src/kinds.rs create mode 100644 third_party/crates/rnix-0.14.0/src/lib.rs create mode 100644 third_party/crates/rnix-0.14.0/src/macros.rs create mode 100644 third_party/crates/rnix-0.14.0/src/parser.rs create mode 100644 third_party/crates/rnix-0.14.0/src/tests.rs create mode 100644 third_party/crates/rnix-0.14.0/src/token_set.rs create mode 100644 third_party/crates/rnix-0.14.0/src/tokenizer.rs create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/dollar_ident_attrpath_issue174.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/dollar_ident_attrpath_issue174.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/error.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/error.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/extra_comma.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/extra_comma.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/formals_double_bind.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/formals_double_bind.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_from_late.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_from_late.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_incomplete.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_incomplete.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_bare_tilde.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_bare_tilde.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_double_slash.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_double_slash.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_no_separator.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_no_separator.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_trailing_slash.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_trailing_slash.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_multiple_errors.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_multiple_errors.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_store_interp.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_store_interp.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde_slash.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde_slash.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_trailing_slash.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/path_trailing_slash.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/select_both_errors.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/select_both_errors.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root2.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root2.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/apply.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/apply.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/assert.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/assert.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrpath_ident.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrpath_ident.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrset.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrset.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_dynamic.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_dynamic.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_empty.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_empty.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_rec.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_rec.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/bool_arith_ops.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/bool_arith_ops.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops_eq.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops_eq.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-arg.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-arg.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-ident.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-ident.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-lambda.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-lambda.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-no-shadow.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-no-shadow.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-bind.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-bind.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field-default.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field-default.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/docs.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/docs.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/has_attr_prec.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/has_attr_prec.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/if_elseif_else.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/if_elseif_else.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/import_nixpkgs.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/import_nixpkgs.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/inherit.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/inherit.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/inherit_dynamic.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/inherit_dynamic.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/interpolation.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/interpolation.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_is_not_uri.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_is_not_uri.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_list.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_list.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_nested.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_nested.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/let.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/let.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/let_legacy.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/let_legacy.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/list.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/list.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/list_concat.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/list_concat.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/math.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/math.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/math2.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/math2.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/math_no_ws.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/math_no_ws.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/merge.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/merge.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/multiple.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/multiple.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/number_list.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/number_list.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/operators_right_assoc.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/operators_right_assoc.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/or-as-ident.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/or-as-ident.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/or_in_attr.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/or_in_attr.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_abs_interp_start.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_abs_interp_start.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_complex_mix.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_complex_mix.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp_no_prefix.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp_no_prefix.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_no_newline.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/path_no_newline.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_left.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_left.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_right.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_right.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_attrset.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_attrset.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_ellipsis.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_ellipsis.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_ellipsis.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_ellipsis.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_trailing_comma.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_trailing_comma.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_assoc.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_assoc.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_math.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_math.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed_math.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed_math.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_assoc.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_assoc.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_math.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_math.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/select_default.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/select_default.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/select_ident.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/select_ident.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/select_string_dynamic.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/select_string_dynamic.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_complex_url.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_complex_url.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_escape_issue175.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_escape_issue175.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_ident.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_ident.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_nested.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_nested.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_select.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_select.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/trivia.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/trivia.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/uri_various.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/uri_various.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/with-import-let-in.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/with-import-let-in.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/with.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/parser/success/with.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_double_slash_middle.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_double_slash_middle.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_home_double_slash.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_home_double_slash.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_interp_trailing_slash.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_interp_trailing_slash.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde_slash.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde_slash.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_trailing_slash.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_trailing_slash.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_interspersed.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_interspersed.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline2.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline2.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_leading_part.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_leading_part.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_trailing_part.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_trailing_part.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_lower.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_lower.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_neg.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_neg.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_pos.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_pos.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_upper.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_upper.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/int.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/int.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda_arg_underscore.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda_arg_underscore.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_01.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_01.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_02.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_02.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_numbers.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_numbers.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/let.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/let.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list_concat.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list_concat.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_div_isnt_path.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_div_isnt_path.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_no_ws.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_no_ws.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_geq_isnt_path.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_geq_isnt_path.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_update.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_update.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start_suffix.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start_suffix.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_nix_store.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_nix_store.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_absolute.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_absolute.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home_hidden.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home_hidden.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_apply.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_apply.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple2.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple2.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_then_plain.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_then_plain.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_isnt_math.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_isnt_math.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_no_newline.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_no_newline.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_operators_mix.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_operators_mix.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_complex.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_complex.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_prefix.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_prefix.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_complex.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_complex.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_with_dash.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_with_dash.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_store.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_store.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_underscore.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_underscore.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_numbers.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_numbers.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_plus.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_plus.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/patterns.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/patterns.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/select_dynamic.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/select_dynamic.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_dollar_escape.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_dollar_escape.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_escape.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_escape.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_dollar_escape.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_dollar_escape.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_nested.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_nested.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_select.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_select.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_isnt_path.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_isnt_path.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_dollar_escape.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_dollar_escape.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_interp_escape.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_interp_escape.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_git_ssh.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_git_ssh.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_https.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_https.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_with_underscore.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_with_underscore.nix create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/with.expect create mode 100644 third_party/crates/rnix-0.14.0/test_data/tokenizer/success/with.nix create mode 100644 third_party/crates/rowan-0.16.1/.cargo-checksum.json create mode 100644 third_party/crates/rowan-0.16.1/.cargo_vcs_info.json create mode 100644 third_party/crates/rowan-0.16.1/BUILD.bazel create mode 100644 third_party/crates/rowan-0.16.1/Cargo.lock create mode 100644 third_party/crates/rowan-0.16.1/Cargo.toml create mode 100644 third_party/crates/rowan-0.16.1/Cargo.toml.orig create mode 100644 third_party/crates/rowan-0.16.1/LICENSE-APACHE create mode 100644 third_party/crates/rowan-0.16.1/LICENSE-MIT create mode 100644 third_party/crates/rowan-0.16.1/README.md create mode 100644 third_party/crates/rowan-0.16.1/examples/math.rs create mode 100644 third_party/crates/rowan-0.16.1/examples/s_expressions.rs create mode 100644 third_party/crates/rowan-0.16.1/src/api.rs create mode 100644 third_party/crates/rowan-0.16.1/src/arc.rs create mode 100644 third_party/crates/rowan-0.16.1/src/ast.rs create mode 100644 third_party/crates/rowan-0.16.1/src/cow_mut.rs create mode 100644 third_party/crates/rowan-0.16.1/src/cursor.rs create mode 100644 third_party/crates/rowan-0.16.1/src/green.rs create mode 100644 third_party/crates/rowan-0.16.1/src/green/builder.rs create mode 100644 third_party/crates/rowan-0.16.1/src/green/element.rs create mode 100644 third_party/crates/rowan-0.16.1/src/green/node.rs create mode 100644 third_party/crates/rowan-0.16.1/src/green/node_cache.rs create mode 100644 third_party/crates/rowan-0.16.1/src/green/token.rs create mode 100644 third_party/crates/rowan-0.16.1/src/lib.rs create mode 100644 third_party/crates/rowan-0.16.1/src/serde_impls.rs create mode 100644 third_party/crates/rowan-0.16.1/src/sll.rs create mode 100644 third_party/crates/rowan-0.16.1/src/syntax_text.rs create mode 100644 third_party/crates/rowan-0.16.1/src/utility_types.rs create mode 100644 third_party/crates/rowan-0.16.1/tests/tidy.rs create mode 100644 third_party/crates/rustc-hash-1.1.0/.cargo-checksum.json create mode 100644 third_party/crates/rustc-hash-1.1.0/.cargo_vcs_info.json create mode 100644 third_party/crates/rustc-hash-1.1.0/BUILD.bazel create mode 100644 third_party/crates/rustc-hash-1.1.0/CODE_OF_CONDUCT.md create mode 100644 third_party/crates/rustc-hash-1.1.0/Cargo.toml create mode 100644 third_party/crates/rustc-hash-1.1.0/Cargo.toml.orig create mode 100644 third_party/crates/rustc-hash-1.1.0/LICENSE-APACHE create mode 100644 third_party/crates/rustc-hash-1.1.0/LICENSE-MIT create mode 100644 third_party/crates/rustc-hash-1.1.0/README.md create mode 100644 third_party/crates/rustc-hash-1.1.0/src/lib.rs create mode 100644 third_party/crates/text-size-1.1.1/.cargo-checksum.json create mode 100644 third_party/crates/text-size-1.1.1/.cargo_vcs_info.json create mode 100644 third_party/crates/text-size-1.1.1/.github/workflows/ci.yaml create mode 100644 third_party/crates/text-size-1.1.1/BUILD.bazel create mode 100644 third_party/crates/text-size-1.1.1/CHANGELOG.md create mode 100644 third_party/crates/text-size-1.1.1/Cargo.toml create mode 100644 third_party/crates/text-size-1.1.1/Cargo.toml.orig create mode 100644 third_party/crates/text-size-1.1.1/LICENSE-APACHE create mode 100644 third_party/crates/text-size-1.1.1/LICENSE-MIT create mode 100644 third_party/crates/text-size-1.1.1/README.md create mode 100644 third_party/crates/text-size-1.1.1/bors.toml create mode 100644 third_party/crates/text-size-1.1.1/src/lib.rs create mode 100644 third_party/crates/text-size-1.1.1/src/range.rs create mode 100644 third_party/crates/text-size-1.1.1/src/serde_impls.rs create mode 100644 third_party/crates/text-size-1.1.1/src/size.rs create mode 100644 third_party/crates/text-size-1.1.1/src/traits.rs create mode 100644 third_party/crates/text-size-1.1.1/tests/auto_traits.rs create mode 100644 third_party/crates/text-size-1.1.1/tests/constructors.rs create mode 100644 third_party/crates/text-size-1.1.1/tests/indexing.rs create mode 100644 third_party/crates/text-size-1.1.1/tests/main.rs create mode 100644 third_party/crates/text-size-1.1.1/tests/serde.rs diff --git a/Cargo.lock b/Cargo.lock index 3fa0230..cb93237 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,6 +107,25 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + +[[package]] +name = "direct-cargo-bazel-deps" +version = "0.0.1" +dependencies = [ + "rnix", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.5.0" @@ -159,6 +178,33 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rnix" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c163bd17372eecdf10d351c34584b7de7c1a33be4e92a32f3fb3f5a7fe3f579b" +dependencies = [ + "rowan", +] + +[[package]] +name = "rowan" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21" +dependencies = [ + "countme", + "hashbrown", + "rustc-hash", + "text-size", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "serde" version = "1.0.229" @@ -219,6 +265,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "text-size" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" + [[package]] name = "unicode-ident" version = "1.0.24" diff --git a/third_party/BUILD b/third_party/BUILD index 185241a..0a39475 100644 --- a/third_party/BUILD +++ b/third_party/BUILD @@ -1,4 +1,4 @@ -load("@rules_rust//crate_universe:defs.bzl", "crates_vendor") +load("@rules_rust//crate_universe:defs.bzl", "crate", "crates_vendor") sh_binary( name = "bazel_for_cargo_bazel", @@ -10,6 +10,11 @@ crates_vendor( bazel = ":bazel_for_cargo_bazel", cargo_lockfile = "//:Cargo.lock", manifests = ["//:Cargo.toml"], + packages = { + "rnix": crate.spec( + version = "=0.14.0", + ), + }, mode = "local", tags = ["manual"], vendor_path = "crates", diff --git a/third_party/crates/BUILD.bazel b/third_party/crates/BUILD.bazel index b491927..f06367d 100644 --- a/third_party/crates/BUILD.bazel +++ b/third_party/crates/BUILD.bazel @@ -43,6 +43,18 @@ alias( tags = ["manual"], ) +alias( + name = "rnix-0.14.0", + actual = "//third_party/crates/rnix-0.14.0:rnix", + tags = ["manual"], +) + +alias( + name = "rnix", + actual = "//third_party/crates/rnix-0.14.0:rnix", + tags = ["manual"], +) + alias( name = "serde-1.0.229", actual = "//third_party/crates/serde-1.0.229:serde", diff --git a/third_party/crates/countme-3.0.1/.cargo-checksum.json b/third_party/crates/countme-3.0.1/.cargo-checksum.json new file mode 100644 index 0000000..a01a16e --- /dev/null +++ b/third_party/crates/countme-3.0.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"c515c26023d43f1a2e58e72f727db7d9fa7262b6f8e08701c7841d2b0296a734",".vscode/settings.json":"2c3e2e5cbc3e4a0955637ed821f4105311669b187302034284200ad8bd387c38","Cargo.lock":"4101e28468b7a3c7a051247ff0d55ea1f2ba58e303857a7a4d3bbaef5caf31cc","Cargo.toml":"5ba3effabbc65115689252c397fb98adb04ac0174819612ecc4e754cea3acf1b","Cargo.toml.orig":"bb43c057350c53f12d2264c1bcbed48c4d181e34ea7de3a21060c97c0f7346e3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"8a8a5d00072b2f1c99a47b50e45cd2604485d1ce1b242eb7dd2895d4c8ca8625","examples/bench.rs":"a081e78268bdfd452840aa23d607bdfac0f57197ca6af35a5832e888fa59ddd2","examples/bench_single_thread.rs":"3e39d60ccb10cbd2905eaa154592af7024c690432f62f09b8211f9d601b39ab0","examples/print_at_exit.rs":"86ace893845110a7035a6aaab71c43640729f374a4be8224e9c559c6fe52f457","src/imp.rs":"dee6f26cd36f8c4062371349f7ff6091aff236edf3e4cccf3d898386dcf0f5bd","src/lib.rs":"c993efcdef9eed3c149f19d2429c59849381c7f61b264741c4ca1696de918974"},"package":"7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"} \ No newline at end of file diff --git a/third_party/crates/countme-3.0.1/.cargo_vcs_info.json b/third_party/crates/countme-3.0.1/.cargo_vcs_info.json new file mode 100644 index 0000000..c3e651e --- /dev/null +++ b/third_party/crates/countme-3.0.1/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "9e037c4293fb8ef6c1c632094349734955f06d89" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/countme-3.0.1/.vscode/settings.json b/third_party/crates/countme-3.0.1/.vscode/settings.json new file mode 100644 index 0000000..5e3e51b --- /dev/null +++ b/third_party/crates/countme-3.0.1/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.cargo.features": ["enable", "print_at_exit"] +} diff --git a/third_party/crates/countme-3.0.1/BUILD.bazel b/third_party/crates/countme-3.0.1/BUILD.bazel new file mode 100644 index 0000000..1719b20 --- /dev/null +++ b/third_party/crates/countme-3.0.1/BUILD.bazel @@ -0,0 +1,110 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "countme", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_root = "src/lib.rs", + edition = "2018", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=countme", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "3.0.1", +) diff --git a/third_party/crates/countme-3.0.1/Cargo.lock b/third_party/crates/countme-3.0.1/Cargo.lock new file mode 100644 index 0000000..1021083 --- /dev/null +++ b/third_party/crates/countme-3.0.1/Cargo.lock @@ -0,0 +1,168 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "countme" +version = "3.0.1" +dependencies = [ + "dashmap", + "once_cell", + "rustc-hash", +] + +[[package]] +name = "dashmap" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0834a35a3fce649144119e18da2a4d8ed12ef3862f47183fd46f625d072d96c" +dependencies = [ + "cfg-if", + "num_cpus", + "parking_lot", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" + +[[package]] +name = "lock_api" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "redox_syscall" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" diff --git a/third_party/crates/countme-3.0.1/Cargo.toml b/third_party/crates/countme-3.0.1/Cargo.toml new file mode 100644 index 0000000..675dea0 --- /dev/null +++ b/third_party/crates/countme-3.0.1/Cargo.toml @@ -0,0 +1,48 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "countme" +version = "3.0.1" +authors = ["Aleksey Kladov "] +exclude = [".github/", "bors.toml", "rustfmt.toml"] +description = "Counts the number of live instances of types" +categories = ["development-tools::profiling"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/matklad/countme" + +[[example]] +name = "print_at_exit" +required-features = ["print_at_exit"] + +[[example]] +name = "bench" +required-features = ["enable"] + +[[example]] +name = "bench_single_thread" +required-features = ["enable"] +[dependencies.dashmap] +version = "5.0" +optional = true + +[dependencies.once_cell] +version = "1.5" +optional = true + +[dependencies.rustc-hash] +version = "1.1" +optional = true + +[features] +enable = ["dashmap", "once_cell", "rustc-hash"] +print_at_exit = ["enable"] diff --git a/third_party/crates/countme-3.0.1/Cargo.toml.orig b/third_party/crates/countme-3.0.1/Cargo.toml.orig new file mode 100644 index 0000000..9931f77 --- /dev/null +++ b/third_party/crates/countme-3.0.1/Cargo.toml.orig @@ -0,0 +1,35 @@ +[package] +name = "countme" +description = "Counts the number of live instances of types" +version = "3.0.1" +categories = ["development-tools::profiling"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/matklad/countme" +authors = ["Aleksey Kladov "] +edition = "2018" + +exclude = [".github/", "bors.toml", "rustfmt.toml"] + +[workspace] +members = ["xtask"] + +[[example]] +name = "print_at_exit" +required-features = ["print_at_exit"] + +[[example]] +name = "bench" +required-features = ["enable"] + +[[example]] +name = "bench_single_thread" +required-features = ["enable"] + +[dependencies] +dashmap = { version = "5.0", optional = true } +once_cell = { version = "1.5", optional = true } +rustc-hash = { version = "1.1", optional = true } + +[features] +enable = [ "dashmap", "once_cell", "rustc-hash" ] +print_at_exit = ["enable"] diff --git a/third_party/crates/countme-3.0.1/LICENSE-APACHE b/third_party/crates/countme-3.0.1/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/third_party/crates/countme-3.0.1/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/third_party/crates/countme-3.0.1/LICENSE-MIT b/third_party/crates/countme-3.0.1/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/countme-3.0.1/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/third_party/crates/countme-3.0.1/README.md b/third_party/crates/countme-3.0.1/README.md new file mode 100644 index 0000000..42f3c7e --- /dev/null +++ b/third_party/crates/countme-3.0.1/README.md @@ -0,0 +1,21 @@ +A library to quickly get the live/total/max counts of allocated instances. + +```rust +#[derive(Default)] +struct Widget { + _c: countme::Count, + ... +} + +let w1 = Widget::default(); +let w2 = Widget::default(); +let w3 = Widget::default(); +drop(w1); + +let counts = countme::get::(); +assert_eq!(counts.live, 2); +assert_eq!(counts.max_live, 3); +assert_eq!(counts.total, 3); + +eprintln!("{}", countme::get_all()); +``` diff --git a/third_party/crates/countme-3.0.1/examples/bench.rs b/third_party/crates/countme-3.0.1/examples/bench.rs new file mode 100644 index 0000000..1f9cc96 --- /dev/null +++ b/third_party/crates/countme-3.0.1/examples/bench.rs @@ -0,0 +1,69 @@ +use std::thread; + +use countme::{get, Count}; + +#[derive(Default)] +struct Foo { + _c: Count, +} + +#[derive(Default)] +struct Bar { + _c: Count, + _x: i32, +} + +mod deeply { + pub(crate) mod nested { + pub(crate) mod module { + use countme::Count; + + #[derive(Default)] + pub(crate) struct Quux { + _c: Count, + } + } + } +} + +fn main() { + countme::enable(true); + let t = std::time::Instant::now(); + let n = 5; + let m = 1_000_000; + + let mut threads = Vec::new(); + for _ in 0..n { + threads.push(thread::spawn(move || { + for _ in 0..m { + Foo::default(); + } + })); + threads.push(thread::spawn(move || { + let mut xs = Vec::with_capacity(m); + for _ in 0..m { + xs.push(Bar::default()) + } + })); + threads.push(thread::spawn(move || { + for _ in 0..m { + deeply::nested::module::Quux::default(); + } + })); + } + for t in threads { + t.join().unwrap(); + } + + let foo = get::(); + assert_eq!(foo.total, m * n); + assert!(foo.max_live >= 1); + assert_eq!(foo.live, 0); + + let bar = get::(); + assert_eq!(bar.total, m * n); + assert!(bar.max_live >= m); + assert_eq!(bar.live, 0); + + println!("{:?}", t.elapsed()); +} diff --git a/third_party/crates/countme-3.0.1/examples/bench_single_thread.rs b/third_party/crates/countme-3.0.1/examples/bench_single_thread.rs new file mode 100644 index 0000000..ac147f8 --- /dev/null +++ b/third_party/crates/countme-3.0.1/examples/bench_single_thread.rs @@ -0,0 +1,77 @@ +use countme::{get, Count}; + +#[derive(Default)] +struct Foo { + _c: Count, +} + +#[derive(Default)] +struct Bar { + _c: Count, + _x: i32, +} + +mod deeply { + pub(crate) mod nested { + pub(crate) mod module { + use countme::Count; + + #[derive(Default)] + pub(crate) struct Quux { + _c: Count, + } + } + } +} + +fn main() { + countme::enable(true); + let t = std::time::Instant::now(); + let n = 6; + let m = 2_000_000; + + for _ in 0..n { + for _ in 0..m { + Foo::default(); + } + + let mut xs = Vec::with_capacity(m); + for _ in 0..m { + xs.push(Bar::default()) + } + + for _ in 0..m { + deeply::nested::module::Quux::default(); + } + + let fs = [ + || drop(Foo::default()), + || drop(Bar::default()), + || drop(deeply::nested::module::Quux::default()), + || { + #[derive(Default)] + struct Local(Count); + + Local::default(); + }, + ]; + for i in 0..m { + fs[i % 4](); + } + } + + let foo = get::(); + assert_eq!(foo.total, m * n + (m * n / 4)); + assert_eq!(foo.max_live, 1); + assert_eq!(foo.live, 0); + + let bar = get::(); + assert_eq!(bar.total, m * n + (m * n / 4)); + + // FIXME: why +1? This seems like a bug + // overreporting by 1 is not significant, but anyway + assert_eq!(bar.max_live, m + 1); + assert_eq!(bar.live, 0); + + println!("{:?}", t.elapsed()); +} diff --git a/third_party/crates/countme-3.0.1/examples/print_at_exit.rs b/third_party/crates/countme-3.0.1/examples/print_at_exit.rs new file mode 100644 index 0000000..fd51e22 --- /dev/null +++ b/third_party/crates/countme-3.0.1/examples/print_at_exit.rs @@ -0,0 +1,11 @@ +#[derive(Default)] +struct Widget { + _t: countme::Count, +} + +fn main() { + let w1 = Widget::default(); + let _w2 = Widget::default(); + drop(w1); + let _w3 = Widget::default(); +} diff --git a/third_party/crates/countme-3.0.1/src/imp.rs b/third_party/crates/countme-3.0.1/src/imp.rs new file mode 100644 index 0000000..c1ace0d --- /dev/null +++ b/third_party/crates/countme-3.0.1/src/imp.rs @@ -0,0 +1,175 @@ +use std::{ + any::{type_name, TypeId}, + cell::RefCell, + collections::HashMap, + hash::BuildHasherDefault, + os::raw::c_int, + sync::atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed}, + sync::Arc, +}; + +use dashmap::DashMap; +use once_cell::sync::OnceCell; +use rustc_hash::FxHasher; + +use crate::{AllCounts, Counts}; + +static ENABLE: AtomicBool = AtomicBool::new(cfg!(feature = "print_at_exit")); + +type GlobalStore = DashMap, BuildHasherDefault>; + +#[inline] +fn global_store() -> &'static GlobalStore { + static MAP: OnceCell = OnceCell::new(); + MAP.get_or_init(|| { + if cfg!(feature = "print_at_exit") { + extern "C" { + fn atexit(f: extern "C" fn()) -> c_int; + } + extern "C" fn print_at_exit() { + eprint!("{}", get_all()); + } + unsafe { + atexit(print_at_exit); + } + } + + GlobalStore::default() + }) +} + +thread_local! { + static LOCAL: RefCell, BuildHasherDefault>> = RefCell::default(); +} + +pub(crate) fn enable(yes: bool) { + ENABLE.store(yes, Relaxed); +} + +#[inline] +fn enabled() -> bool { + ENABLE.load(Relaxed) +} + +#[inline] +pub(crate) fn dec() { + if enabled() { + do_dec(TypeId::of::()) + } +} +#[inline(never)] +fn do_dec(key: TypeId) { + LOCAL.with(|local| { + // Fast path: we have needed store in thread local map + if let Some(store) = local.borrow().get(&key) { + store.dec(); + return; + } + + let global = global_store(); + + // Slightly slower: we don't have needed store in our thread local map, + // but some other thread has already initialized the needed store in the global map + if let Some(store) = global.get(&key) { + let store = store.value(); + local.borrow_mut().insert(key, Arc::clone(store)); + store.inc(); + return; + } + + // We only decrement counter after incremenrting it, so this line is unreachable + }) +} + +#[inline] +pub(crate) fn inc() { + if enabled() { + do_inc(TypeId::of::(), type_name::()) + } +} +#[inline(never)] +fn do_inc(key: TypeId, name: &'static str) { + LOCAL.with(|local| { + // Fast path: we have needed store in thread local map + if let Some(store) = local.borrow().get(&key) { + store.inc(); + return; + } + + let global = global_store(); + + let copy = match global.get(&key) { + // Slightly slower path: we don't have needed store in our thread local map, + // but some other thread has already initialized the needed store in the global map + Some(store) => { + let store = store.value(); + store.inc(); + Arc::clone(store) + } + // Slow path: we are the first to initialize both global and local maps + None => { + let store = global + .entry(key) + .or_insert_with(|| Arc::new(Store { name, ..Store::default() })) + .downgrade(); + let store = store.value(); + + store.inc(); + Arc::clone(store) + } + }; + + local.borrow_mut().insert(key, copy); + }); +} + +pub(crate) fn get() -> Counts { + do_get(TypeId::of::()) +} +fn do_get(key: TypeId) -> Counts { + global_store().entry(key).or_default().value().read() +} + +pub(crate) fn get_all() -> AllCounts { + let mut entries = global_store() + .iter() + .map(|entry| { + let store = entry.value(); + (store.type_name(), store.read()) + }) + .collect::>(); + entries.sort_by_key(|(name, _counts)| *name); + AllCounts { entries } +} + +#[derive(Default)] +struct Store { + total: AtomicUsize, + max_live: AtomicUsize, + live: AtomicUsize, + name: &'static str, +} + +impl Store { + fn inc(&self) { + self.total.fetch_add(1, Relaxed); + let live = self.live.fetch_add(1, Relaxed) + 1; + self.max_live.fetch_max(live, Relaxed); + } + + fn dec(&self) { + self.live.fetch_sub(1, Relaxed); + } + + fn read(&self) -> Counts { + Counts { + total: self.total.load(Relaxed), + max_live: self.max_live.load(Relaxed), + live: self.live.load(Relaxed), + } + } + + fn type_name(&self) -> &'static str { + self.name + } +} diff --git a/third_party/crates/countme-3.0.1/src/lib.rs b/third_party/crates/countme-3.0.1/src/lib.rs new file mode 100644 index 0000000..f89e63c --- /dev/null +++ b/third_party/crates/countme-3.0.1/src/lib.rs @@ -0,0 +1,193 @@ +//! A library to quickly get the live/total/max counts of allocated instances. +//! +//! # Example +//! +//! ``` +//! # if cfg!(not(feature = "enable")) { return; } +//! +//! #[derive(Default)] +//! struct Widget { +//! _c: countme::Count, +//! } +//! +//! countme::enable(true); +//! +//! let w1 = Widget::default(); +//! let w2 = Widget::default(); +//! let w3 = Widget::default(); +//! drop(w1); +//! +//! let counts = countme::get::(); +//! assert_eq!(counts.live, 2); +//! assert_eq!(counts.max_live, 3); +//! assert_eq!(counts.total, 3); +//! +//! eprintln!("{}", countme::get_all()); +//! ``` +//! +//! # Configuration +//! +//! By default, the implementation compiles to no-ops. Therefore it is possible +//! to include `Count` fields into library types. +//! +//! The `enable` cargo feature ungates the counting code. The feature can be +//! enabled anywhere in the crate graph. +//! +//! At run-time, the counters are controlled with [`enable`] function. Counting +//! is enabled by default if `print_at_exit` feature is enabled. Otherwise +//! counting is disabled by default. Call `enable(true)` early in `main` to enable: +//! +//! ```rust +//! fn main() { +//! countme::enable(std::env::var("COUNTME").is_ok()); +//! } +//! ``` +//! +//! The code is optimized for the case where counting is not enabled at runtime +//! (counting is a relaxed load and a branch to a function call). +//! +//! The `print_at_exit` Cargo feature uses `atexit` call to print final counts +//! before the program exits (it also enables counting at runtime). Use it only +//! when you can't modify the main to print counts -- `atexit` is not guaranteed +//! to work with rust's runtime. +#[cfg(feature = "enable")] +mod imp; + +use std::{fmt, marker::PhantomData}; + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[non_exhaustive] +pub struct Counts { + /// The total number of tokens created. + pub total: usize, + /// The historical maximum of the `live` count. + pub max_live: usize, + /// The number of tokens which were created, but are not destroyed yet. + pub live: usize, +} + +/// Store this inside your struct as `_c: countme::Count`. +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Count { + ghost: PhantomData, +} + +impl Default for Count { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl Clone for Count { + #[inline] + fn clone(&self) -> Self { + Self::new() + } +} + +impl Count { + /// Create new `Count`, incrementing the corresponding count. + #[inline] + pub fn new() -> Count { + #[cfg(feature = "enable")] + imp::inc::(); + Count { ghost: PhantomData } + } +} + +impl Drop for Count { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "enable")] + imp::dec::(); + } +} + +/// Enable or disable counting at runtime. +/// +/// Counting is enabled by default if `print_at_exit` feature is enabled. +/// Otherwise counting is disabled by default. +/// +/// If neither `enable` nor `print_at_exit` features are enabled, then this function is noop. +pub fn enable(_yes: bool) { + #[cfg(feature = "enable")] + imp::enable(_yes); +} + +/// Returns the counts for the `T` type. +#[inline] +pub fn get() -> Counts { + #[cfg(feature = "enable")] + { + return imp::get::(); + } + #[cfg(not(feature = "enable"))] + { + return Counts::default(); + } +} + +/// Returns a collection of counts for all types. +pub fn get_all() -> AllCounts { + #[cfg(feature = "enable")] + { + return imp::get_all(); + } + #[cfg(not(feature = "enable"))] + { + return AllCounts::default(); + } +} + +/// A collection of counts for all types. +#[derive(Default, Clone, Debug)] +pub struct AllCounts { + entries: Vec<(&'static str, Counts)>, +} + +impl fmt::Display for AllCounts { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn sep(mut n: usize) -> String { + let mut groups = Vec::new(); + while n >= 1000 { + groups.push(format!("{:03}", n % 1000)); + n /= 1000; + } + groups.push(n.to_string()); + groups.reverse(); + groups.join("_") + } + + if self.entries.is_empty() { + return if cfg!(feature = "enable") { + writeln!(f, "all counts are zero") + } else { + writeln!(f, "counts are disabled") + }; + } + let max_width = + self.entries.iter().map(|(name, _count)| name.chars().count()).max().unwrap_or(0); + for (name, counts) in &self.entries { + writeln!( + f, + "{:12} {:>12} {:>12}", + name, + sep(counts.total), + sep(counts.max_live), + sep(counts.live), + max_width = max_width + )?; + } + writeln!( + f, + "{:12} {:>12} {:>12}", + "", + "total", + "max_live", + "live", + max_width = max_width + )?; + Ok(()) + } +} diff --git a/third_party/crates/crates.bzl b/third_party/crates/crates.bzl index 88c3e25..2f08651 100644 --- a/third_party/crates/crates.bzl +++ b/third_party/crates/crates.bzl @@ -310,11 +310,17 @@ def aliases( ############################################################################### _CRATE_EDITIONS = { + "": "2018", "src/ariadne": "2024", "src/machoke": "2024", } _NORMAL_DEPENDENCIES = { + "": { + _COMMON_CONDITION: { + "rnix": Label("//third_party/crates/rnix-0.14.0:rnix"), + }, + }, "src/ariadne": { _COMMON_CONDITION: { "clap": Label("//third_party/crates/clap-4.6.6:clap"), @@ -327,6 +333,10 @@ _NORMAL_DEPENDENCIES = { } _NORMAL_ALIASES = { + "": { + _COMMON_CONDITION: { + }, + }, "src/ariadne": { _COMMON_CONDITION: { }, @@ -336,6 +346,8 @@ _NORMAL_ALIASES = { } _NORMAL_DEV_DEPENDENCIES = { + "": { + }, "src/ariadne": { }, "src/machoke": { @@ -343,6 +355,8 @@ _NORMAL_DEV_DEPENDENCIES = { } _NORMAL_DEV_ALIASES = { + "": { + }, "src/ariadne": { }, "src/machoke": { @@ -350,6 +364,8 @@ _NORMAL_DEV_ALIASES = { } _PROC_MACRO_DEPENDENCIES = { + "": { + }, "src/ariadne": { }, "src/machoke": { @@ -357,6 +373,8 @@ _PROC_MACRO_DEPENDENCIES = { } _PROC_MACRO_ALIASES = { + "": { + }, "src/ariadne": { }, "src/machoke": { @@ -364,6 +382,8 @@ _PROC_MACRO_ALIASES = { } _PROC_MACRO_DEV_DEPENDENCIES = { + "": { + }, "src/ariadne": { }, "src/machoke": { @@ -371,6 +391,8 @@ _PROC_MACRO_DEV_DEPENDENCIES = { } _PROC_MACRO_DEV_ALIASES = { + "": { + }, "src/ariadne": { }, "src/machoke": { @@ -378,6 +400,8 @@ _PROC_MACRO_DEV_ALIASES = { } _BUILD_DEPENDENCIES = { + "": { + }, "src/ariadne": { }, "src/machoke": { @@ -385,6 +409,8 @@ _BUILD_DEPENDENCIES = { } _BUILD_ALIASES = { + "": { + }, "src/ariadne": { }, "src/machoke": { @@ -392,6 +418,8 @@ _BUILD_ALIASES = { } _BUILD_PROC_MACRO_DEPENDENCIES = { + "": { + }, "src/ariadne": { }, "src/machoke": { @@ -399,6 +427,8 @@ _BUILD_PROC_MACRO_DEPENDENCIES = { } _BUILD_PROC_MACRO_ALIASES = { + "": { + }, "src/ariadne": { }, "src/machoke": { diff --git a/third_party/crates/hashbrown-0.14.5/.cargo-checksum.json b/third_party/crates/hashbrown-0.14.5/.cargo-checksum.json new file mode 100644 index 0000000..06f7b2f --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"b1f17aefeca2e91526393fbf93f76ddb51f4c1693746a8f598bfb0f3444a7a6f","CHANGELOG.md":"1a844fe3b7466b41ca1d5914af197d5aeed7cb14f30ebe4be351367d7ca905d2","Cargo.toml":"c011f10385da722056537329f3fcf8c9b93af742e79e38885c0152a0105fc227","Cargo.toml.orig":"6d7350ae61b9df7a42e4e2293fbfa8cc5a7ab351732d45e178dcfc7b413d3819","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"84c222ce49510535419d338b7532a72a2bf22b7466e44de78d92d25b6c7d636b","benches/bench.rs":"ef7bc025922f077d307c565640c005d056e3d6c1713448a95aae92d3c22c1005","benches/insert_unique_unchecked.rs":"cb84275f22d5f95a5ac995ac6b2df74ffcf342765b401d27c95f2955c7b7cb9f","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"0625e6a5e3b8ecc8901a12aeeea54393fd84617fb3a14d98a34d2d2bddb8d257","src/external_trait_impls/rayon/helpers.rs":"ba105bf0853ebc45157f22116ad0f55d3bdab75e721d8e7a677c7b912d0c0c6d","src/external_trait_impls/rayon/map.rs":"96fdf39b3f601f77152d7ce84541b8f51f32b9274b7da9c294862892e721a5d8","src/external_trait_impls/rayon/mod.rs":"126edc882501dddd25e442d9236508b5b386eb8c0a9f5d654f2dd081086c1616","src/external_trait_impls/rayon/raw.rs":"04012fb2e99648819b4bc0044107ed3cb94013e242b7865075c5bd9ebf1b6865","src/external_trait_impls/rayon/set.rs":"7539348ff7bc6e3cce6b3c019d62dc401eea0138c578fef729c2593e8ead1cfa","src/external_trait_impls/rayon/table.rs":"8778d29509c68b5b7cb66859db025d3939ce22e7cf370b20ff3dea4fe4b29fd0","src/external_trait_impls/rkyv/hash_map.rs":"7abe24318143b776016052b05840656afc858b1ba5252f3d418d61972477f53d","src/external_trait_impls/rkyv/hash_set.rs":"38d969125d17d606492ec4ec9fc06b7e7118eb903240dacf40de21b9b06fa5c8","src/external_trait_impls/rkyv/mod.rs":"54399ce5574fd1d84b7b0cb4238fa3e898575e89a6724299be009d2172bda02e","src/external_trait_impls/serde.rs":"6dbe104dee16b453b6b048b541c6e02c6d067d970dfafd243fc4360288b0168c","src/lib.rs":"74e250c18e55994a4a902eaa06aca034559d6de53501ed4bf9010fabc67e88a2","src/macros.rs":"98a26b908fc0fbe6a58d008a317e550013d615eb3cc17a5054a573c62c1d74cb","src/map.rs":"d484f2f81e5b4acf4b615f187241e34c3016aaaca53a5e71019cceb993c4ebd7","src/raw/alloc.rs":"902f8588d0fdee3e5c3dc02410f41d4b38ac88843727387f929f3186b3a2d322","src/raw/bitmask.rs":"3b3dce8d6a48856ada19085abf43908f124ab3419fcf434b9ca64d7bff243f67","src/raw/generic.rs":"efc5e603be3e9a17935aef1836a38ce01c78a0093b2af0671548eb5459b37921","src/raw/mod.rs":"16bbabf42dde9f3fb17c4f7e768aef47752d839bf624b81d24a48af3d418b3a2","src/raw/neon.rs":"9907d8ebc36fc3df562dde478ea9b72213fda65288a304718d8647f0029dc9ad","src/raw/sse2.rs":"39038e3344e49f4638e211bcdbf56565ac53e90dce56172cc3b526fea911c2af","src/rustc_entry.rs":"8142ed89b50155602ef8c1628382bd62d3ee903920fe49d403d4100a278c6ba4","src/scopeguard.rs":"1a246e08a63c06cd8ad934bd7da229421bf804f991ae93cd7e242da27ca6c601","src/set.rs":"a620ed68bd1610b76c4c1890615d71b2c04928bf5b345133a0588a065bce06fa","src/table.rs":"7b7174099d2e3cade0caeddd73e29b7395f3b9f4f1f21013f885b52cd93438cb","tests/equivalent_trait.rs":"84faa3fe9d67c375d03fec81f0f1412c47862477d42e84e7d235258236338d5b","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/raw.rs":"43ed2f98877533a0905611d9a30f26b183dd3e103e3856eeab80e7b8ac7894d3","tests/rayon.rs":"39cb24ab45fce8087bb54948715c8b6973ebfba1a325292b5b3cd9aab50b5fd2","tests/serde.rs":"6bac8054db722dd049901b37a6e006535bac30f425eb5cd91af19b5bc1dfe78e","tests/set.rs":"9f8011c29d1059aadb54b6dd4623521d5178b4278b4a56021ef2cee4bbb19fd9"},"package":"e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"} \ No newline at end of file diff --git a/third_party/crates/hashbrown-0.14.5/.cargo_vcs_info.json b/third_party/crates/hashbrown-0.14.5/.cargo_vcs_info.json new file mode 100644 index 0000000..71be784 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "025d0f58b62d074f5fd660a22fe293cdc237d589" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/hashbrown-0.14.5/BUILD.bazel b/third_party/crates/hashbrown-0.14.5/BUILD.bazel new file mode 100644 index 0000000..25b04cc --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/BUILD.bazel @@ -0,0 +1,113 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "hashbrown", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "inline-more", + ], + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=hashbrown", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "0.14.5", +) diff --git a/third_party/crates/hashbrown-0.14.5/CHANGELOG.md b/third_party/crates/hashbrown-0.14.5/CHANGELOG.md new file mode 100644 index 0000000..8c40680 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/CHANGELOG.md @@ -0,0 +1,532 @@ +# Change Log + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/) +and this project adheres to [Semantic Versioning](https://semver.org/). + +## [Unreleased] + +### Changed + +- Changed `hash_set::{Entry, VacantEntry}::insert` to return `OccupiedEntry`. (#495) + +## [v0.14.5] - 2024-04-28 + +### Fixed + +- Fixed index calculation in panic guard of `clone_from_impl`. (#511) + +## ~~[v0.14.4] - 2024-03-19~~ + +This release was _yanked_ due to a breaking change. + +## [v0.14.3] - 2023-11-26 + +### Added + +- Specialized `fold` implementation of iterators. (#480) + +### Fixed + +- Avoid using unstable `ptr::invalid_mut` on nightly. (#481) + +## [v0.14.2] - 2023-10-19 + +### Added + +- `HashTable` type which provides a low-level but safe API with explicit hashing. (#466) + +### Fixed + +- Disabled the use of NEON instructions on big-endian ARM. (#475) +- Disabled the use of NEON instructions on Miri. (#476) + +## [v0.14.1] - 2023-09-28 + +### Added + +- Allow serializing `HashMap`s that use a custom allocator. (#449) + +### Changed + +- Use the `Equivalent` trait from the `equivalent` crate. (#442) +- Slightly improved performance of table resizing. (#451) +- Relaxed MSRV to 1.63.0. (#457) +- Removed `Clone` requirement from custom allocators. (#468) + +### Fixed + +- Fixed custom allocators being leaked in some situations. (#439, #465) + +## [v0.14.0] - 2023-06-01 + +### Added + +- Support for `allocator-api2` crate + for interfacing with custom allocators on stable. (#417) +- Optimized implementation for ARM using NEON instructions. (#430) +- Support for rkyv serialization. (#432) +- `Equivalent` trait to look up values without `Borrow`. (#345) +- `Hash{Map,Set}::raw_table_mut` is added whic returns a mutable reference. (#404) +- Fast path for `clear` on empty tables. (#428) + +### Changed + +- Optimized insertion to only perform a single lookup. (#277) +- `DrainFilter` (`drain_filter`) has been renamed to `ExtractIf` and no longer drops remaining + elements when the iterator is dropped. #(374) +- Bumped MSRV to 1.64.0. (#431) +- `{Map,Set}::raw_table` now returns an immutable reference. (#404) +- `VacantEntry` and `OccupiedEntry` now use the default hasher if none is + specified in generics. (#389) +- `RawTable::data_start` now returns a `NonNull` to match `RawTable::data_end`. (#387) +- `RawIter::{reflect_insert, reflect_remove}` are now unsafe. (#429) +- `RawTable::find_potential` is renamed to `find_or_find_insert_slot` and returns an `InsertSlot`. (#429) +- `RawTable::remove` now also returns an `InsertSlot`. (#429) +- `InsertSlot` can be used to insert an element with `RawTable::insert_in_slot`. (#429) +- `RawIterHash` no longer has a lifetime tied to that of the `RawTable`. (#427) +- The trait bounds of `HashSet::raw_table` have been relaxed to not require `Eq + Hash`. (#423) +- `EntryRef::and_replace_entry_with` and `OccupiedEntryRef::replace_entry_with` + were changed to give a `&K` instead of a `&Q` to the closure. + +### Removed + +- Support for `bumpalo` as an allocator with custom wrapper. + Use `allocator-api2` feature in `bumpalo` to use it as an allocator + for `hashbrown` collections. (#417) + +## [v0.13.2] - 2023-01-12 + +### Fixed + +- Added `#[inline(always)]` to `find_inner`. (#375) +- Fixed `RawTable::allocation_info` for empty tables. (#376) + +## [v0.13.1] - 2022-11-10 + +### Added + +- Added `Equivalent` trait to customize key lookups. (#350) +- Added support for 16-bit targets. (#368) +- Added `RawTable::allocation_info` which provides information about the memory + usage of a table. (#371) + +### Changed + +- Bumped MSRV to 1.61.0. +- Upgraded to `ahash` 0.8. (#357) +- Make `with_hasher_in` const. (#355) +- The following methods have been removed from the `RawTable` API in favor of + safer alternatives: + - `RawTable::erase_no_drop` => Use `RawTable::erase` or `RawTable::remove` instead. + - `Bucket::read` => Use `RawTable::remove` instead. + - `Bucket::drop` => Use `RawTable::erase` instead. + - `Bucket::write` => Use `Bucket::as_mut` instead. + +### Fixed + +- Ensure that `HashMap` allocations don't exceed `isize::MAX`. (#362) +- Fixed issue with field retagging in scopeguard. (#359) + +## [v0.12.3] - 2022-07-17 + +### Fixed + +- Fixed double-drop in `RawTable::clone_from`. (#348) + +## [v0.12.2] - 2022-07-09 + +### Added + +- Added `Entry` API for `HashSet`. (#342) +- Added `Extend<&'a (K, V)> for HashMap`. (#340) +- Added length-based short-circuiting for hash table iteration. (#338) +- Added a function to access the `RawTable` of a `HashMap`. (#335) + +### Changed + +- Edited `do_alloc` to reduce LLVM IR generated. (#341) + +## [v0.12.1] - 2022-05-02 + +### Fixed + +- Fixed underflow in `RawIterRange::size_hint`. (#325) +- Fixed the implementation of `Debug` for `ValuesMut` and `IntoValues`. (#325) + +## [v0.12.0] - 2022-01-17 + +### Added + +- Added `From<[T; N]>` and `From<[(K, V); N]>` for `HashSet` and `HashMap` respectively. (#297) +- Added an `allocator()` getter to HashMap and HashSet. (#257) +- Added `insert_unique_unchecked` to `HashMap` and `HashSet`. (#293) +- Added `into_keys` and `into_values` to HashMap. (#295) +- Implement `From` on `HashSet` and `HashMap`. (#298) +- Added `entry_ref` API to `HashMap`. (#201) + +### Changed + +- Bumped minimum Rust version to 1.56.1 and edition to 2021. +- Use u64 for the GroupWord on WebAssembly. (#271) +- Optimized `find`. (#279) +- Made rehashing and resizing less generic to reduce compilation time. (#282) +- Inlined small functions. (#283) +- Use `BuildHasher::hash_one` when `feature = "nightly"` is enabled. (#292) +- Relaxed the bounds on `Debug` for `HashSet`. (#296) +- Rename `get_each_mut` to `get_many_mut` and align API with the stdlib. (#291) +- Don't hash the key when searching in an empty table. (#305) + +### Fixed + +- Guard against allocations exceeding isize::MAX. (#268) +- Made `RawTable::insert_no_grow` unsafe. (#254) +- Inline `static_empty`. (#280) +- Fixed trait bounds on Send/Sync impls. (#303) + +## [v0.11.2] - 2021-03-25 + +### Fixed + +- Added missing allocator type parameter to `HashMap`'s and `HashSet`'s `Clone` impls. (#252) + +## [v0.11.1] - 2021-03-20 + +### Fixed + +- Added missing `pub` modifier to `BumpWrapper`. (#251) + +## [v0.11.0] - 2021-03-14 + +### Added +- Added safe `try_insert_no_grow` method to `RawTable`. (#229) +- Added support for `bumpalo` as an allocator without the `nightly` feature. (#231) +- Implemented `Default` for `RawTable`. (#237) +- Added new safe methods `RawTable::get_each_mut`, `HashMap::get_each_mut`, and + `HashMap::get_each_key_value_mut`. (#239) +- Added `From>` for `HashSet`. (#235) +- Added `try_insert` method to `HashMap`. (#247) + +### Changed +- The minimum Rust version has been bumped to 1.49.0. (#230) +- Significantly improved compilation times by reducing the amount of generated IR. (#205) + +### Removed +- We no longer re-export the unstable allocator items from the standard library, nor the stable shims approximating the same. (#227) +- Removed hasher specialization support from `aHash`, which was resulting in inconsistent hashes being generated for a key. (#248) + +### Fixed +- Fixed union length comparison. (#228) + +## ~~[v0.10.0] - 2021-01-16~~ + +This release was _yanked_ due to inconsistent hashes being generated with the `nightly` feature. (#248) + +### Changed +- Parametrized `RawTable`, `HashSet` and `HashMap` over an allocator. (#133) +- Improved branch prediction hints on stable. (#209) +- Optimized hashing of primitive types with AHash using specialization. (#207) +- Only instantiate `RawTable`'s reserve functions once per key-value. (#204) + +## [v0.9.1] - 2020-09-28 + +### Added +- Added safe methods to `RawTable` (#202): + - `get`: `find` and `as_ref` + - `get_mut`: `find` and `as_mut` + - `insert_entry`: `insert` and `as_mut` + - `remove_entry`: `find` and `remove` + - `erase_entry`: `find` and `erase` + +### Changed +- Removed `from_key_hashed_nocheck`'s `Q: Hash`. (#200) +- Made `RawTable::drain` safe. (#201) + +## [v0.9.0] - 2020-09-03 + +### Fixed +- `drain_filter` now removes and yields items that do match the predicate, + rather than items that don't. This is a **breaking change** to match the + behavior of the `drain_filter` methods in `std`. (#187) + +### Added +- Added `replace_entry_with` to `OccupiedEntry`, and `and_replace_entry_with` to `Entry`. (#190) +- Implemented `FusedIterator` and `size_hint` for `DrainFilter`. (#188) + +### Changed +- The minimum Rust version has been bumped to 1.36 (due to `crossbeam` dependency). (#193) +- Updated `ahash` dependency to 0.4. (#198) +- `HashMap::with_hasher` and `HashSet::with_hasher` are now `const fn`. (#195) +- Removed `T: Hash + Eq` and `S: BuildHasher` bounds on `HashSet::new`, + `with_capacity`, `with_hasher`, and `with_capacity_and_hasher`. (#185) + +## [v0.8.2] - 2020-08-08 + +### Changed +- Avoid closures to improve compile times. (#183) +- Do not iterate to drop if empty. (#182) + +## [v0.8.1] - 2020-07-16 + +### Added +- Added `erase` and `remove` to `RawTable`. (#171) +- Added `try_with_capacity` to `RawTable`. (#174) +- Added methods that allow re-using a `RawIter` for `RawDrain`, + `RawIntoIter`, and `RawParIter`. (#175) +- Added `reflect_remove` and `reflect_insert` to `RawIter`. (#175) +- Added a `drain_filter` function to `HashSet`. (#179) + +### Changed +- Deprecated `RawTable::erase_no_drop` in favor of `erase` and `remove`. (#176) +- `insert_no_grow` is now exposed under the `"raw"` feature. (#180) + +## [v0.8.0] - 2020-06-18 + +### Fixed +- Marked `RawTable::par_iter` as `unsafe`. (#157) + +### Changed +- Reduced the size of `HashMap`. (#159) +- No longer create tables with a capacity of 1 element. (#162) +- Removed `K: Eq + Hash` bounds on `retain`. (#163) +- Pulled in `HashMap` changes from rust-lang/rust (#164): + - `extend_one` support on nightly. + - `CollectionAllocErr` renamed to `TryReserveError`. + - Added `HashSet::get_or_insert_owned`. + - `Default` for `HashSet` no longer requires `T: Eq + Hash` and `S: BuildHasher`. + +## [v0.7.2] - 2020-04-27 + +### Added +- Added `or_insert_with_key` to `Entry`. (#152) + +### Fixed +- Partially reverted `Clone` optimization which was unsound. (#154) + +### Changed +- Disabled use of `const-random` by default, which prevented reproducible builds. (#155) +- Optimized `repeat` function. (#150) +- Use `NonNull` for buckets, which improves codegen for iterators. (#148) + +## [v0.7.1] - 2020-03-16 + +### Added +- Added `HashMap::get_key_value_mut`. (#145) + +### Changed +- Optimized `Clone` implementation. (#146) + +## [v0.7.0] - 2020-01-31 + +### Added +- Added a `drain_filter` function to `HashMap`. (#135) + +### Changed +- Updated `ahash` dependency to 0.3. (#141) +- Optimized set union and intersection. (#130) +- `raw_entry` can now be used without requiring `S: BuildHasher`. (#123) +- `RawTable::bucket_index` can now be used under the `raw` feature. (#128) + +## [v0.6.3] - 2019-10-31 + +### Added +- Added an `ahash-compile-time-rng` feature (enabled by default) which allows disabling the + `compile-time-rng` feature in `ahash` to work around a Cargo bug. (#125) + +## [v0.6.2] - 2019-10-23 + +### Added +- Added an `inline-more` feature (enabled by default) which allows choosing a tradeoff between + runtime performance and compilation time. (#119) + +## [v0.6.1] - 2019-10-04 + +### Added +- Added `Entry::insert` and `RawEntryMut::insert`. (#118) + +### Changed +- `Group::static_empty` was changed from a `const` to a `static` (#116). + +## [v0.6.0] - 2019-08-13 + +### Fixed +- Fixed AHash accidentally depending on `std`. (#110) + +### Changed +- The minimum Rust version has been bumped to 1.32 (due to `rand` dependency). + +## ~~[v0.5.1] - 2019-08-04~~ + +This release was _yanked_ due to a breaking change for users of `no-default-features`. + +### Added +- The experimental and unsafe `RawTable` API is available under the "raw" feature. (#108) +- Added entry-like methods for `HashSet`. (#98) + +### Changed +- Changed the default hasher from FxHash to AHash. (#97) +- `hashbrown` is now fully `no_std` on recent Rust versions (1.36+). (#96) + +### Fixed +- We now avoid growing the table during insertions when it wasn't necessary. (#106) +- `RawOccupiedEntryMut` now properly implements `Send` and `Sync`. (#100) +- Relaxed `lazy_static` version. (#92) + +## [v0.5.0] - 2019-06-12 + +### Fixed +- Resize with a more conservative amount of space after deletions. (#86) + +### Changed +- Exposed the Layout of the failed allocation in CollectionAllocErr::AllocErr. (#89) + +## [v0.4.0] - 2019-05-30 + +### Fixed +- Fixed `Send` trait bounds on `IterMut` not matching the libstd one. (#82) + +## [v0.3.1] - 2019-05-30 + +### Fixed +- Fixed incorrect use of slice in unsafe code. (#80) + +## [v0.3.0] - 2019-04-23 + +### Changed +- Changed shrink_to to not panic if min_capacity < capacity. (#67) + +### Fixed +- Worked around emscripten bug emscripten-core/emscripten-fastcomp#258. (#66) + +## [v0.2.2] - 2019-04-16 + +### Fixed +- Inlined non-nightly lowest_set_bit_nonzero. (#64) +- Fixed build on latest nightly. (#65) + +## [v0.2.1] - 2019-04-14 + +### Changed +- Use for_each in map Extend and FromIterator. (#58) +- Improved worst-case performance of HashSet.is_subset. (#61) + +### Fixed +- Removed incorrect debug_assert. (#60) + +## [v0.2.0] - 2019-03-31 + +### Changed +- The code has been updated to Rust 2018 edition. This means that the minimum + Rust version has been bumped to 1.31 (2018 edition). + +### Added +- Added `insert_with_hasher` to the raw_entry API to allow `K: !(Hash + Eq)`. (#54) +- Added support for using hashbrown as the hash table implementation in libstd. (#46) + +### Fixed +- Fixed cargo build with minimal-versions. (#45) +- Fixed `#[may_dangle]` attributes to match the libstd `HashMap`. (#46) +- ZST keys and values are now handled properly. (#46) + +## [v0.1.8] - 2019-01-14 + +### Added +- Rayon parallel iterator support (#37) +- `raw_entry` support (#31) +- `#[may_dangle]` on nightly (#31) +- `try_reserve` support (#31) + +### Fixed +- Fixed variance on `IterMut`. (#31) + +## [v0.1.7] - 2018-12-05 + +### Fixed +- Fixed non-SSE version of convert_special_to_empty_and_full_to_deleted. (#32) +- Fixed overflow in rehash_in_place. (#33) + +## [v0.1.6] - 2018-11-17 + +### Fixed +- Fixed compile error on nightly. (#29) + +## [v0.1.5] - 2018-11-08 + +### Fixed +- Fixed subtraction overflow in generic::Group::match_byte. (#28) + +## [v0.1.4] - 2018-11-04 + +### Fixed +- Fixed a bug in the `erase_no_drop` implementation. (#26) + +## [v0.1.3] - 2018-11-01 + +### Added +- Serde support. (#14) + +### Fixed +- Make the compiler inline functions more aggressively. (#20) + +## [v0.1.2] - 2018-10-31 + +### Fixed +- `clear` segfaults when called on an empty table. (#13) + +## [v0.1.1] - 2018-10-30 + +### Fixed +- `erase_no_drop` optimization not triggering in the SSE2 implementation. (#3) +- Missing `Send` and `Sync` for hash map and iterator types. (#7) +- Bug when inserting into a table smaller than the group width. (#5) + +## v0.1.0 - 2018-10-29 + +- Initial release + +[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.14.5...HEAD +[v0.14.5]: https://github.com/rust-lang/hashbrown/compare/v0.14.4...v0.14.5 +[v0.14.4]: https://github.com/rust-lang/hashbrown/compare/v0.14.3...v0.14.4 +[v0.14.3]: https://github.com/rust-lang/hashbrown/compare/v0.14.2...v0.14.3 +[v0.14.2]: https://github.com/rust-lang/hashbrown/compare/v0.14.1...v0.14.2 +[v0.14.1]: https://github.com/rust-lang/hashbrown/compare/v0.14.0...v0.14.1 +[v0.14.0]: https://github.com/rust-lang/hashbrown/compare/v0.13.2...v0.14.0 +[v0.13.2]: https://github.com/rust-lang/hashbrown/compare/v0.13.1...v0.13.2 +[v0.13.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.3...v0.13.1 +[v0.12.3]: https://github.com/rust-lang/hashbrown/compare/v0.12.2...v0.12.3 +[v0.12.2]: https://github.com/rust-lang/hashbrown/compare/v0.12.1...v0.12.2 +[v0.12.1]: https://github.com/rust-lang/hashbrown/compare/v0.12.0...v0.12.1 +[v0.12.0]: https://github.com/rust-lang/hashbrown/compare/v0.11.2...v0.12.0 +[v0.11.2]: https://github.com/rust-lang/hashbrown/compare/v0.11.1...v0.11.2 +[v0.11.1]: https://github.com/rust-lang/hashbrown/compare/v0.11.0...v0.11.1 +[v0.11.0]: https://github.com/rust-lang/hashbrown/compare/v0.10.0...v0.11.0 +[v0.10.0]: https://github.com/rust-lang/hashbrown/compare/v0.9.1...v0.10.0 +[v0.9.1]: https://github.com/rust-lang/hashbrown/compare/v0.9.0...v0.9.1 +[v0.9.0]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...v0.9.0 +[v0.8.2]: https://github.com/rust-lang/hashbrown/compare/v0.8.1...v0.8.2 +[v0.8.1]: https://github.com/rust-lang/hashbrown/compare/v0.8.0...v0.8.1 +[v0.8.0]: https://github.com/rust-lang/hashbrown/compare/v0.7.2...v0.8.0 +[v0.7.2]: https://github.com/rust-lang/hashbrown/compare/v0.7.1...v0.7.2 +[v0.7.1]: https://github.com/rust-lang/hashbrown/compare/v0.7.0...v0.7.1 +[v0.7.0]: https://github.com/rust-lang/hashbrown/compare/v0.6.3...v0.7.0 +[v0.6.3]: https://github.com/rust-lang/hashbrown/compare/v0.6.2...v0.6.3 +[v0.6.2]: https://github.com/rust-lang/hashbrown/compare/v0.6.1...v0.6.2 +[v0.6.1]: https://github.com/rust-lang/hashbrown/compare/v0.6.0...v0.6.1 +[v0.6.0]: https://github.com/rust-lang/hashbrown/compare/v0.5.1...v0.6.0 +[v0.5.1]: https://github.com/rust-lang/hashbrown/compare/v0.5.0...v0.5.1 +[v0.5.0]: https://github.com/rust-lang/hashbrown/compare/v0.4.0...v0.5.0 +[v0.4.0]: https://github.com/rust-lang/hashbrown/compare/v0.3.1...v0.4.0 +[v0.3.1]: https://github.com/rust-lang/hashbrown/compare/v0.3.0...v0.3.1 +[v0.3.0]: https://github.com/rust-lang/hashbrown/compare/v0.2.2...v0.3.0 +[v0.2.2]: https://github.com/rust-lang/hashbrown/compare/v0.2.1...v0.2.2 +[v0.2.1]: https://github.com/rust-lang/hashbrown/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/rust-lang/hashbrown/compare/v0.1.8...v0.2.0 +[v0.1.8]: https://github.com/rust-lang/hashbrown/compare/v0.1.7...v0.1.8 +[v0.1.7]: https://github.com/rust-lang/hashbrown/compare/v0.1.6...v0.1.7 +[v0.1.6]: https://github.com/rust-lang/hashbrown/compare/v0.1.5...v0.1.6 +[v0.1.5]: https://github.com/rust-lang/hashbrown/compare/v0.1.4...v0.1.5 +[v0.1.4]: https://github.com/rust-lang/hashbrown/compare/v0.1.3...v0.1.4 +[v0.1.3]: https://github.com/rust-lang/hashbrown/compare/v0.1.2...v0.1.3 +[v0.1.2]: https://github.com/rust-lang/hashbrown/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/rust-lang/hashbrown/compare/v0.1.0...v0.1.1 diff --git a/third_party/crates/hashbrown-0.14.5/Cargo.toml b/third_party/crates/hashbrown-0.14.5/Cargo.toml new file mode 100644 index 0000000..0a5434e --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/Cargo.toml @@ -0,0 +1,137 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.63.0" +name = "hashbrown" +version = "0.14.5" +authors = ["Amanieu d'Antras "] +exclude = [ + ".github", + "/ci/*", +] +description = "A Rust port of Google's SwissTable hash map" +readme = "README.md" +keywords = [ + "hash", + "no_std", + "hashmap", + "swisstable", +] +categories = [ + "data-structures", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/hashbrown" + +[package.metadata.docs.rs] +features = [ + "nightly", + "rayon", + "serde", + "raw", +] +rustdoc-args = ["--generate-link-to-definition"] + +[dependencies.ahash] +version = "0.8.7" +optional = true +default-features = false + +[dependencies.alloc] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-alloc" + +[dependencies.allocator-api2] +version = "0.2.9" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" + +[dependencies.equivalent] +version = "1.0" +optional = true +default-features = false + +[dependencies.rayon] +version = "1.0" +optional = true + +[dependencies.rkyv] +version = "0.7.42" +features = ["alloc"] +optional = true +default-features = false + +[dependencies.serde] +version = "1.0.25" +optional = true +default-features = false + +[dev-dependencies.bumpalo] +version = "3.13.0" +features = ["allocator-api2"] + +[dev-dependencies.doc-comment] +version = "0.3.1" + +[dev-dependencies.fnv] +version = "1.0.7" + +[dev-dependencies.lazy_static] +version = "1.4" + +[dev-dependencies.rand] +version = "0.8.3" +features = ["small_rng"] + +[dev-dependencies.rayon] +version = "1.0" + +[dev-dependencies.rkyv] +version = "0.7.42" +features = ["validation"] + +[dev-dependencies.serde_test] +version = "1.0" + +[features] +default = [ + "ahash", + "inline-more", + "allocator-api2", +] +inline-more = [] +nightly = [ + "allocator-api2?/nightly", + "bumpalo/allocator_api", +] +raw = [] +rustc-dep-of-std = [ + "nightly", + "core", + "compiler_builtins", + "alloc", + "rustc-internal-api", +] +rustc-internal-api = [] diff --git a/third_party/crates/hashbrown-0.14.5/Cargo.toml.orig b/third_party/crates/hashbrown-0.14.5/Cargo.toml.orig new file mode 100644 index 0000000..7e50b43 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/Cargo.toml.orig @@ -0,0 +1,71 @@ +[package] +name = "hashbrown" +version = "0.14.5" +authors = ["Amanieu d'Antras "] +description = "A Rust port of Google's SwissTable hash map" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/hashbrown" +readme = "README.md" +keywords = ["hash", "no_std", "hashmap", "swisstable"] +categories = ["data-structures", "no-std"] +exclude = [".github", "/ci/*"] +edition = "2021" +rust-version = "1.63.0" + +[dependencies] +# For the default hasher +ahash = { version = "0.8.7", default-features = false, optional = true } + +# For external trait impls +rayon = { version = "1.0", optional = true } +serde = { version = "1.0.25", default-features = false, optional = true } +rkyv = { version = "0.7.42", optional = true, default-features = false, features = [ + "alloc", +] } + +# When built as part of libstd +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +compiler_builtins = { version = "0.1.2", optional = true } +alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } + +# Support for allocators that use allocator-api2 +allocator-api2 = { version = "0.2.9", optional = true, default-features = false, features = [ + "alloc", +] } + +# Equivalent trait which can be shared with other hash table implementations. +equivalent = { version = "1.0", optional = true, default-features = false } + +[dev-dependencies] +lazy_static = "1.4" +rand = { version = "0.8.3", features = ["small_rng"] } +rayon = "1.0" +fnv = "1.0.7" +serde_test = "1.0" +doc-comment = "0.3.1" +bumpalo = { version = "3.13.0", features = ["allocator-api2"] } +rkyv = { version = "0.7.42", features = ["validation"] } + +[features] +default = ["ahash", "inline-more", "allocator-api2"] + +nightly = ["allocator-api2?/nightly", "bumpalo/allocator_api"] + +rustc-internal-api = [] +rustc-dep-of-std = [ + "nightly", + "core", + "compiler_builtins", + "alloc", + "rustc-internal-api", +] +raw = [] + +# Enables usage of `#[inline]` on far more functions than by default in this +# crate. This may lead to a performance increase but often comes at a compile +# time cost. +inline-more = [] + +[package.metadata.docs.rs] +features = ["nightly", "rayon", "serde", "raw"] +rustdoc-args = ["--generate-link-to-definition"] diff --git a/third_party/crates/hashbrown-0.14.5/LICENSE-APACHE b/third_party/crates/hashbrown-0.14.5/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/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/third_party/crates/hashbrown-0.14.5/LICENSE-MIT b/third_party/crates/hashbrown-0.14.5/LICENSE-MIT new file mode 100644 index 0000000..5afc2a7 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Amanieu d'Antras + +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/third_party/crates/hashbrown-0.14.5/README.md b/third_party/crates/hashbrown-0.14.5/README.md new file mode 100644 index 0000000..5eaef8b --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/README.md @@ -0,0 +1,125 @@ +hashbrown +========= + +[![Build Status](https://github.com/rust-lang/hashbrown/actions/workflows/rust.yml/badge.svg)](https://github.com/rust-lang/hashbrown/actions) +[![Crates.io](https://img.shields.io/crates/v/hashbrown.svg)](https://crates.io/crates/hashbrown) +[![Documentation](https://docs.rs/hashbrown/badge.svg)](https://docs.rs/hashbrown) +[![Rust](https://img.shields.io/badge/rust-1.63.0%2B-blue.svg?maxAge=3600)](https://github.com/rust-lang/hashbrown) + +This crate is a Rust port of Google's high-performance [SwissTable] hash +map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +and `HashSet` types. + +The original C++ version of SwissTable can be found [here], and this +[CppCon talk] gives an overview of how the algorithm works. + +Since Rust 1.36, this is now the `HashMap` implementation for the Rust standard +library. However you may still want to use this crate instead since it works +in environments without `std`, such as embedded systems and kernels. + +[SwissTable]: https://abseil.io/blog/20180927-swisstables +[here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +[CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +## [Change log](CHANGELOG.md) + +## Features + +- Drop-in replacement for the standard library `HashMap` and `HashSet` types. +- Uses [AHash](https://github.com/tkaitchuck/aHash) as the default hasher, which is much faster than SipHash. + However, AHash does *not provide the same level of HashDoS resistance* as SipHash, so if that is important to you, you might want to consider using a different hasher. +- Around 2x faster than the previous standard library `HashMap`. +- Lower memory usage: only 1 byte of overhead per entry instead of 8. +- Compatible with `#[no_std]` (but requires a global allocator with the `alloc` crate). +- Empty hash maps do not allocate any memory. +- SIMD lookups to scan multiple hash entries in parallel. + +## Performance + +Compared to the previous implementation of `std::collections::HashMap` (Rust 1.35). + +With the hashbrown default AHash hasher: + +| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | +| :-------------------------- | :----------------: | ----------------: | :----------: | ------: | ------- | +| insert_ahash_highbits | 18,865 | 8,020 | -10,845 | -57.49% | x 2.35 | +| insert_ahash_random | 19,711 | 8,019 | -11,692 | -59.32% | x 2.46 | +| insert_ahash_serial | 19,365 | 6,463 | -12,902 | -66.63% | x 3.00 | +| insert_erase_ahash_highbits | 51,136 | 17,916 | -33,220 | -64.96% | x 2.85 | +| insert_erase_ahash_random | 51,157 | 17,688 | -33,469 | -65.42% | x 2.89 | +| insert_erase_ahash_serial | 45,479 | 14,895 | -30,584 | -67.25% | x 3.05 | +| iter_ahash_highbits | 1,399 | 1,092 | -307 | -21.94% | x 1.28 | +| iter_ahash_random | 1,586 | 1,059 | -527 | -33.23% | x 1.50 | +| iter_ahash_serial | 3,168 | 1,079 | -2,089 | -65.94% | x 2.94 | +| lookup_ahash_highbits | 32,351 | 4,792 | -27,559 | -85.19% | x 6.75 | +| lookup_ahash_random | 17,419 | 4,817 | -12,602 | -72.35% | x 3.62 | +| lookup_ahash_serial | 15,254 | 3,606 | -11,648 | -76.36% | x 4.23 | +| lookup_fail_ahash_highbits | 21,187 | 4,369 | -16,818 | -79.38% | x 4.85 | +| lookup_fail_ahash_random | 21,550 | 4,395 | -17,155 | -79.61% | x 4.90 | +| lookup_fail_ahash_serial | 19,450 | 3,176 | -16,274 | -83.67% | x 6.12 | + + +With the libstd default SipHash hasher: + +| name | oldstdhash ns/iter | hashbrown ns/iter | diff ns/iter | diff % | speedup | +| :------------------------ | :----------------: | ----------------: | :----------: | ------: | ------- | +| insert_std_highbits | 19,216 | 16,885 | -2,331 | -12.13% | x 1.14 | +| insert_std_random | 19,179 | 17,034 | -2,145 | -11.18% | x 1.13 | +| insert_std_serial | 19,462 | 17,493 | -1,969 | -10.12% | x 1.11 | +| insert_erase_std_highbits | 50,825 | 35,847 | -14,978 | -29.47% | x 1.42 | +| insert_erase_std_random | 51,448 | 35,392 | -16,056 | -31.21% | x 1.45 | +| insert_erase_std_serial | 87,711 | 38,091 | -49,620 | -56.57% | x 2.30 | +| iter_std_highbits | 1,378 | 1,159 | -219 | -15.89% | x 1.19 | +| iter_std_random | 1,395 | 1,132 | -263 | -18.85% | x 1.23 | +| iter_std_serial | 1,704 | 1,105 | -599 | -35.15% | x 1.54 | +| lookup_std_highbits | 17,195 | 13,642 | -3,553 | -20.66% | x 1.26 | +| lookup_std_random | 17,181 | 13,773 | -3,408 | -19.84% | x 1.25 | +| lookup_std_serial | 15,483 | 13,651 | -1,832 | -11.83% | x 1.13 | +| lookup_fail_std_highbits | 20,926 | 13,474 | -7,452 | -35.61% | x 1.55 | +| lookup_fail_std_random | 21,766 | 13,505 | -8,261 | -37.95% | x 1.61 | +| lookup_fail_std_serial | 19,336 | 13,519 | -5,817 | -30.08% | x 1.43 | + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +hashbrown = "0.14" +``` + +Then: + +```rust +use hashbrown::HashMap; + +let mut map = HashMap::new(); +map.insert(1, "one"); +``` +## Flags +This crate has the following Cargo features: + +- `nightly`: Enables nightly-only features including: `#[may_dangle]`. +- `serde`: Enables serde serialization support. +- `rkyv`: Enables rkyv serialization support. +- `rayon`: Enables rayon parallel iterator support. +- `raw`: Enables access to the experimental and unsafe `RawTable` API. +- `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost + of compilation time. (enabled by default) +- `ahash`: Compiles with ahash as default hasher. (enabled by default) +- `allocator-api2`: Enables support for allocators that support `allocator-api2`. (enabled by default) + +## 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/third_party/crates/hashbrown-0.14.5/benches/bench.rs b/third_party/crates/hashbrown-0.14.5/benches/bench.rs new file mode 100644 index 0000000..346bd7e --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/benches/bench.rs @@ -0,0 +1,331 @@ +// This benchmark suite contains some benchmarks along a set of dimensions: +// Hasher: std default (SipHash) and crate default (AHash). +// Int key distribution: low bit heavy, top bit heavy, and random. +// Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter +#![feature(test)] + +extern crate test; + +use test::{black_box, Bencher}; + +use hashbrown::hash_map::DefaultHashBuilder; +use hashbrown::{HashMap, HashSet}; +use std::{ + collections::hash_map::RandomState, + sync::atomic::{self, AtomicUsize}, +}; + +const SIZE: usize = 1000; + +// The default hashmap when using this crate directly. +type AHashMap = HashMap; +// This uses the hashmap from this crate with the default hasher of the stdlib. +type StdHashMap = HashMap; + +// A random key iterator. +#[derive(Clone, Copy)] +struct RandomKeys { + state: usize, +} + +impl RandomKeys { + fn new() -> Self { + RandomKeys { state: 0 } + } +} + +impl Iterator for RandomKeys { + type Item = usize; + fn next(&mut self) -> Option { + // Add 1 then multiply by some 32 bit prime. + self.state = self.state.wrapping_add(1).wrapping_mul(3_787_392_781); + Some(self.state) + } +} + +// Just an arbitrary side effect to make the maps not shortcircuit to the non-dropping path +// when dropping maps/entries (most real world usages likely have drop in the key or value) +lazy_static::lazy_static! { + static ref SIDE_EFFECT: AtomicUsize = AtomicUsize::new(0); +} + +#[derive(Clone)] +struct DropType(usize); +impl Drop for DropType { + fn drop(&mut self) { + SIDE_EFFECT.fetch_add(self.0, atomic::Ordering::SeqCst); + } +} + +macro_rules! bench_suite { + ($bench_macro:ident, $bench_ahash_serial:ident, $bench_std_serial:ident, + $bench_ahash_highbits:ident, $bench_std_highbits:ident, + $bench_ahash_random:ident, $bench_std_random:ident) => { + $bench_macro!($bench_ahash_serial, AHashMap, 0..); + $bench_macro!($bench_std_serial, StdHashMap, 0..); + $bench_macro!( + $bench_ahash_highbits, + AHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!( + $bench_std_highbits, + StdHashMap, + (0..).map(usize::swap_bytes) + ); + $bench_macro!($bench_ahash_random, AHashMap, RandomKeys::new()); + $bench_macro!($bench_std_random, StdHashMap, RandomKeys::new()); + }; +} + +macro_rules! bench_insert { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::with_capacity_and_hasher(SIZE, Default::default()); + b.iter(|| { + m.clear(); + for i in ($keydist).take(SIZE) { + m.insert(i, (DropType(i), [i; 20])); + } + black_box(&mut m); + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_insert, + insert_ahash_serial, + insert_std_serial, + insert_ahash_highbits, + insert_std_highbits, + insert_ahash_random, + insert_std_random +); + +macro_rules! bench_grow_insert { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + b.iter(|| { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + black_box(&mut m); + }) + } + }; +} + +bench_suite!( + bench_grow_insert, + grow_insert_ahash_serial, + grow_insert_std_serial, + grow_insert_ahash_highbits, + grow_insert_std_highbits, + grow_insert_ahash_random, + grow_insert_std_random +); + +macro_rules! bench_insert_erase { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut base = $maptype::default(); + for i in ($keydist).take(SIZE) { + base.insert(i, DropType(i)); + } + let skip = $keydist.skip(SIZE); + b.iter(|| { + let mut m = base.clone(); + let mut add_iter = skip.clone(); + let mut remove_iter = $keydist; + // While keeping the size constant, + // replace the first keydist with the second. + for (add, remove) in (&mut add_iter).zip(&mut remove_iter).take(SIZE) { + m.insert(add, DropType(add)); + black_box(m.remove(&remove)); + } + black_box(m); + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_insert_erase, + insert_erase_ahash_serial, + insert_erase_std_serial, + insert_erase_ahash_highbits, + insert_erase_std_highbits, + insert_erase_ahash_random, + insert_erase_std_random +); + +macro_rules! bench_lookup { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in $keydist.take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in $keydist.take(SIZE) { + black_box(m.get(&i)); + } + }); + eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst)); + } + }; +} + +bench_suite!( + bench_lookup, + lookup_ahash_serial, + lookup_std_serial, + lookup_ahash_highbits, + lookup_std_highbits, + lookup_ahash_random, + lookup_std_random +); + +macro_rules! bench_lookup_fail { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + let mut iter = $keydist; + for i in (&mut iter).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in (&mut iter).take(SIZE) { + black_box(m.get(&i)); + } + }) + } + }; +} + +bench_suite!( + bench_lookup_fail, + lookup_fail_ahash_serial, + lookup_fail_std_serial, + lookup_fail_ahash_highbits, + lookup_fail_std_highbits, + lookup_fail_ahash_random, + lookup_fail_std_random +); + +macro_rules! bench_iter { + ($name:ident, $maptype:ident, $keydist:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut m = $maptype::default(); + for i in ($keydist).take(SIZE) { + m.insert(i, DropType(i)); + } + + b.iter(|| { + for i in &m { + black_box(i); + } + }) + } + }; +} + +bench_suite!( + bench_iter, + iter_ahash_serial, + iter_std_serial, + iter_ahash_highbits, + iter_std_highbits, + iter_ahash_random, + iter_std_random +); + +#[bench] +fn clone_small(b: &mut Bencher) { + let mut m = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }) +} + +#[bench] +fn clone_from_small(b: &mut Bencher) { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + for i in 0..10 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + m2.clone_from(&m); + black_box(&mut m2); + }) +} + +#[bench] +fn clone_large(b: &mut Bencher) { + let mut m = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + black_box(m.clone()); + }) +} + +#[bench] +fn clone_from_large(b: &mut Bencher) { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + for i in 0..1000 { + m.insert(i, DropType(i)); + } + + b.iter(|| { + m2.clone_from(&m); + black_box(&mut m2); + }) +} + +#[bench] +fn rehash_in_place(b: &mut Bencher) { + b.iter(|| { + let mut set = HashSet::new(); + + // Each loop triggers one rehash + for _ in 0..10 { + for i in 0..223 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + set.clear(); + } + }); +} diff --git a/third_party/crates/hashbrown-0.14.5/benches/insert_unique_unchecked.rs b/third_party/crates/hashbrown-0.14.5/benches/insert_unique_unchecked.rs new file mode 100644 index 0000000..857ad18 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/benches/insert_unique_unchecked.rs @@ -0,0 +1,32 @@ +//! Compare `insert` and `insert_unique_unchecked` operations performance. + +#![feature(test)] + +extern crate test; + +use hashbrown::HashMap; +use test::Bencher; + +#[bench] +fn insert(b: &mut Bencher) { + let keys: Vec = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect(); + b.iter(|| { + let mut m = HashMap::with_capacity(1000); + for k in &keys { + m.insert(k, k); + } + m + }); +} + +#[bench] +fn insert_unique_unchecked(b: &mut Bencher) { + let keys: Vec = (0..1000).map(|i| format!("xxxx{}yyyy", i)).collect(); + b.iter(|| { + let mut m = HashMap::with_capacity(1000); + for k in &keys { + m.insert_unique_unchecked(k, k); + } + m + }); +} diff --git a/third_party/crates/hashbrown-0.14.5/clippy.toml b/third_party/crates/hashbrown-0.14.5/clippy.toml new file mode 100644 index 0000000..d98bf2c --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/clippy.toml @@ -0,0 +1 @@ +doc-valid-idents = [ "CppCon", "SwissTable", "SipHash", "HashDoS" ] diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/mod.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/mod.rs new file mode 100644 index 0000000..01d386b --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/mod.rs @@ -0,0 +1,6 @@ +#[cfg(feature = "rayon")] +pub(crate) mod rayon; +#[cfg(feature = "rkyv")] +mod rkyv; +#[cfg(feature = "serde")] +mod serde; diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs new file mode 100644 index 0000000..070b08c --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/helpers.rs @@ -0,0 +1,27 @@ +use alloc::collections::LinkedList; +use alloc::vec::Vec; + +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Helper for collecting parallel iterators to an intermediary +#[allow(clippy::linkedlist)] // yes, we need linked list here for efficient appending! +pub(super) fn collect(iter: I) -> (LinkedList>, usize) { + let list = iter + .into_par_iter() + .fold(Vec::new, |mut vec, elem| { + vec.push(elem); + vec + }) + .map(|vec| { + let mut list = LinkedList::new(); + list.push_back(vec); + list + }) + .reduce(LinkedList::new, |mut list1, mut list2| { + list1.append(&mut list2); + list1 + }); + + let len = list.iter().map(Vec::len).sum(); + (list, len) +} diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs new file mode 100644 index 0000000..2534dc9 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/map.rs @@ -0,0 +1,721 @@ +//! Rayon extensions for `HashMap`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::hash_map::HashMap; +use crate::raw::{Allocator, Global}; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashMap.html#method.par_iter +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to keys in a map. +/// +/// This iterator is created by the [`par_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_keys`]: /hashbrown/struct.HashMap.html#method.par_keys +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParKeys<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().0 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParKeys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParKeys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().0 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over shared references to values in a map. +/// +/// This iterator is created by the [`par_values`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values`]: /hashbrown/struct.HashMap.html#method.par_values +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParValues<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &x.as_ref().1 }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParValues<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParValues<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().1 }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashMap`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: /hashbrown/struct.HashMap.html#method.par_iter_mut +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html +pub struct ParIterMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParIterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { + let r = x.as_mut(); + (&r.0, &mut r.1) + }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over mutable references to values in a map. +/// +/// This iterator is created by the [`par_values_mut`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_values_mut`]: /hashbrown/struct.HashMap.html#method.par_values_mut +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParValuesMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, +} + +impl<'a, K: Sync, V: Send> ParallelIterator for ParValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { &mut x.as_mut().1 }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParValues { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashMap`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashMap.html#method.into_par_iter +/// [`HashMap`]: /hashbrown/struct.HashMap.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: RawIntoParIter<(K, V), A>, +} + +impl ParallelIterator for IntoParIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashMap`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashMap.html#method.par_drain +/// [`HashMap`]: /hashbrown/struct.HashMap.html +pub struct ParDrain<'a, K, V, A: Allocator = Global> { + inner: RawParDrain<'a, (K, V), A>, +} + +impl ParallelIterator for ParDrain<'_, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParDrain<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashMap { + /// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Visits (potentially in parallel) immutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl HashMap { + /// Visits (potentially in parallel) mutably borrowed values in an arbitrary order. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } + + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> { + ParDrain { + inner: self.table.par_drain(), + } + } +} + +impl HashMap +where + K: Eq + Hash + Sync, + V: PartialEq + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + /// Returns `true` if the map is equal to another, + /// i.e. both maps contain the same keys mapped to the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() + && self + .into_par_iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl IntoParallelIterator for HashMap { + type Item = (K, V); + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.table.into_par_iter(), + } + } +} + +impl<'a, K: Sync, V: Sync, S, A: Allocator> IntoParallelIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type Iter = ParIter<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, K: Sync, V: Send, S, A: Allocator> IntoParallelIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type Iter = ParIterMut<'a, K, V>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } + } +} + +/// Collect (key, value) pairs from a parallel iterator into a +/// hashmap. If multiple pairs correspond to the same key, then the +/// ones produced earlier in the parallel iterator will be +/// overwritten, just as with a sequential iterator. +impl FromParallelIterator<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut map = HashMap::default(); + map.par_extend(par_iter); + map + } +} + +/// Extend a hash map with items from a parallel iterator. +impl ParallelExtend<(K, V)> for HashMap +where + K: Eq + Hash + Send, + V: Send, + S: BuildHasher, + A: Allocator, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash map with copied items from a parallel iterator. +impl<'a, K, V, S, A> ParallelExtend<(&'a K, &'a V)> for HashMap +where + K: Copy + Eq + Hash + Sync, + V: Copy + Sync, + S: BuildHasher, + A: Allocator, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashMap` -- no custom advantage. +fn extend(map: &mut HashMap, par_iter: I) +where + K: Eq + Hash, + S: BuildHasher, + I: IntoParallelIterator, + A: Allocator, + HashMap: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire length if the map is empty. + // Otherwise reserve half the length (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if map.is_empty() { len } else { (len + 1) / 2 }; + map.reserve(reserve); + for vec in list { + map.extend(vec); + } +} + +#[cfg(test)] +mod test_par_map { + use alloc::vec::Vec; + use core::hash::{Hash, Hasher}; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::hash_map::HashMap; + + struct Dropable<'a> { + k: usize, + counter: &'a AtomicUsize, + } + + impl Dropable<'_> { + fn new(k: usize, counter: &AtomicUsize) -> Dropable<'_> { + counter.fetch_add(1, Ordering::Relaxed); + + Dropable { k, counter } + } + } + + impl Drop for Dropable<'_> { + fn drop(&mut self) { + self.counter.fetch_sub(1, Ordering::Relaxed); + } + } + + impl Clone for Dropable<'_> { + fn clone(&self) -> Self { + Dropable::new(self.k, self.counter) + } + } + + impl Hash for Dropable<'_> { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.k.hash(state); + } + } + + impl PartialEq for Dropable<'_> { + fn eq(&self, other: &Self) -> bool { + self.k == other.k + } + } + + impl Eq for Dropable<'_> {} + + #[test] + fn test_into_iter_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Dropable::new(i, &key); + let d2 = Dropable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the iterator does not leak anything. + drop(hm.clone().into_par_iter()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm.into_par_iter().filter(|(key, _)| key.k < 50).collect(); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_drain_drops() { + let key = AtomicUsize::new(0); + let value = AtomicUsize::new(0); + + let mut hm = { + let mut hm = HashMap::new(); + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + + for i in 0..100 { + let d1 = Dropable::new(i, &key); + let d2 = Dropable::new(i + 100, &value); + hm.insert(d1, d2); + } + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // Ensure that dropping the drain iterator does not leak anything. + drop(hm.clone().par_drain()); + + { + assert_eq!(key.load(Ordering::Relaxed), 100); + assert_eq!(value.load(Ordering::Relaxed), 100); + + // retain only half + let _v: Vec<_> = hm.drain().filter(|(key, _)| key.k < 50).collect(); + assert!(hm.is_empty()); + + assert_eq!(key.load(Ordering::Relaxed), 50); + assert_eq!(value.load(Ordering::Relaxed), 50); + }; + + assert_eq!(key.load(Ordering::Relaxed), 0); + assert_eq!(value.load(Ordering::Relaxed), 0); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.par_drain().count(), 0); + assert_eq!(m.par_keys().count(), 0); + assert_eq!(m.par_values().count(), 0); + assert_eq!(m.par_values_mut().count(), 0); + assert_eq!(m.par_iter().count(), 0); + assert_eq!(m.par_iter_mut().count(), 0); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_par_iter().count(), 0); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let observed = AtomicUsize::new(0); + + m.par_iter().for_each(|(k, v)| { + assert_eq!(*v, *k * 2); + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let keys: Vec<_> = map.par_keys().cloned().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_par_iter().collect(); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_par_iter().collect(); + map.par_values_mut().for_each(|value| *value *= 2); + let values: Vec<_> = map.par_values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(!m1.par_eq(&m2)); + + m2.insert(3, 4); + + assert!(m1.par_eq(&m2)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.par_iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + } + + #[test] + fn test_extend_ref() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.par_extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs new file mode 100644 index 0000000..61ca69b --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/mod.rs @@ -0,0 +1,5 @@ +mod helpers; +pub(crate) mod map; +pub(crate) mod raw; +pub(crate) mod set; +pub(crate) mod table; diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs new file mode 100644 index 0000000..612be47 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/raw.rs @@ -0,0 +1,230 @@ +use crate::raw::Bucket; +use crate::raw::{Allocator, Global, RawIter, RawIterRange, RawTable}; +use crate::scopeguard::guard; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; +use rayon::iter::{ + plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer}, + ParallelIterator, +}; + +/// Parallel iterator which returns a raw pointer to every full bucket in the table. +pub struct RawParIter { + iter: RawIterRange, +} + +impl RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn iter(&self) -> RawIterRange { + self.iter.clone() + } +} + +impl Clone for RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + } + } +} + +impl From> for RawParIter { + fn from(it: RawIter) -> Self { + RawParIter { iter: it.iter } + } +} + +impl ParallelIterator for RawParIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let producer = ParIterProducer { iter: self.iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Producer which returns a `Bucket` for every element. +struct ParIterProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParIterProducer { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.split(); + let left = ParIterProducer { iter: left }; + let right = right.map(|right| ParIterProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(self, folder: F) -> F + where + F: Folder, + { + folder.consume_iter(self.iter) + } +} + +/// Parallel iterator which consumes a table and returns elements. +pub struct RawIntoParIter { + table: RawTable, +} + +impl RawIntoParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.par_iter() + } +} + +impl ParallelIterator for RawIntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let iter = unsafe { self.table.iter().iter }; + let _guard = guard(self.table.into_allocation(), |alloc| { + if let Some((ptr, layout, ref alloc)) = *alloc { + unsafe { + alloc.deallocate(ptr, layout); + } + } + }); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +/// Parallel iterator which consumes elements without freeing the table storage. +pub struct RawParDrain<'a, T, A: Allocator = Global> { + // We don't use a &'a mut RawTable because we want RawParDrain to be + // covariant over T. + table: NonNull>, + marker: PhantomData<&'a RawTable>, +} + +unsafe impl Send for RawParDrain<'_, T, A> {} + +impl RawParDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.as_ref().par_iter() + } +} + +impl ParallelIterator for RawParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + let _guard = guard(self.table, |table| unsafe { + table.as_mut().clear_no_drop(); + }); + let iter = unsafe { self.table.as_ref().iter().iter }; + mem::forget(self); + let producer = ParDrainProducer { iter }; + plumbing::bridge_unindexed(producer, consumer) + } +} + +impl Drop for RawParDrain<'_, T, A> { + fn drop(&mut self) { + // If drive_unindexed is not called then simply clear the table. + unsafe { + self.table.as_mut().clear(); + } + } +} + +/// Producer which will consume all elements in the range, even if it is dropped +/// halfway through. +struct ParDrainProducer { + iter: RawIterRange, +} + +impl UnindexedProducer for ParDrainProducer { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn split(self) -> (Self, Option) { + let (left, right) = self.iter.clone().split(); + mem::forget(self); + let left = ParDrainProducer { iter: left }; + let right = right.map(|right| ParDrainProducer { iter: right }); + (left, right) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn fold_with(mut self, mut folder: F) -> F + where + F: Folder, + { + // Make sure to modify the iterator in-place so that any remaining + // elements are processed in our Drop impl. + for item in &mut self.iter { + folder = folder.consume(unsafe { item.read() }); + if folder.full() { + return folder; + } + } + + // If we processed all elements then we don't need to run the drop. + mem::forget(self); + folder + } +} + +impl Drop for ParDrainProducer { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + // Drop all remaining elements + if mem::needs_drop::() { + for item in &mut self.iter { + unsafe { + item.drop(); + } + } + } + } +} + +impl RawTable { + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn par_iter(&self) -> RawParIter { + RawParIter { + iter: self.iter().iter, + } + } + + /// Returns a parallel iterator over the elements in a `RawTable`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_par_iter(self) -> RawIntoParIter { + RawIntoParIter { table: self } + } + + /// Returns a parallel iterator which consumes all elements of a `RawTable` + /// without freeing its memory allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> RawParDrain<'_, T, A> { + RawParDrain { + table: NonNull::from(self), + marker: PhantomData, + } + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs new file mode 100644 index 0000000..3de98fc --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/set.rs @@ -0,0 +1,659 @@ +//! Rayon extensions for `HashSet`. + +use super::map; +use crate::hash_set::HashSet; +use crate::raw::{Allocator, Global}; +use core::hash::{BuildHasher, Hash}; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; + +/// Parallel iterator over elements of a consumed set. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashSet.html#method.into_par_iter +/// [`HashSet`]: /hashbrown/struct.HashSet.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: map::IntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel draining iterator over entries of a set. +/// +/// This iterator is created by the [`par_drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashSet.html#method.par_drain +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParDrain<'a, T, A: Allocator = Global> { + inner: map::ParDrain<'a, T, (), A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.map(|(k, _)| k).drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in a set. +/// +/// This iterator is created by the [`par_iter`] method on [`HashSet`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashSet.html#method.par_iter +/// [`HashSet`]: /hashbrown/struct.HashSet.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, T> { + inner: map::ParKeys<'a, T, ()>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the difference of +/// sets. +/// +/// This iterator is created by the [`par_difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_difference`]: /hashbrown/struct.HashSet.html#method.par_difference +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParDifference<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| !self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the symmetric +/// difference of sets. +/// +/// This iterator is created by the [`par_symmetric_difference`] method on +/// [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_symmetric_difference`]: /hashbrown/struct.HashSet.html#method.par_symmetric_difference +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParSymmetricDifference<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParSymmetricDifference<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .par_difference(self.b) + .chain(self.b.par_difference(self.a)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the intersection of +/// sets. +/// +/// This iterator is created by the [`par_intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_intersection`]: /hashbrown/struct.HashSet.html#method.par_intersection +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParIntersection<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParIntersection<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.a + .into_par_iter() + .filter(|&x| self.b.contains(x)) + .drive_unindexed(consumer) + } +} + +/// Parallel iterator over shared references to elements in the union of sets. +/// +/// This iterator is created by the [`par_union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`par_union`]: /hashbrown/struct.HashSet.html#method.par_union +/// [`HashSet`]: /hashbrown/struct.HashSet.html +pub struct ParUnion<'a, T, S, A: Allocator = Global> { + a: &'a HashSet, + b: &'a HashSet, +} + +impl<'a, T, S, A> ParallelIterator for ParUnion<'a, T, S, A> +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + type Item = &'a T; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.a.len() <= self.b.len() { + (self.a, self.b) + } else { + (self.b, self.a) + }; + larger + .into_par_iter() + .chain(smaller.par_difference(larger)) + .drive_unindexed(consumer) + } +} + +impl HashSet +where + T: Eq + Hash + Sync, + S: BuildHasher + Sync, + A: Allocator + Sync, +{ + /// Visits (potentially in parallel) the values representing the union, + /// i.e. all the values in `self` or `other`, without duplicates. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_union<'a>(&'a self, other: &'a Self) -> ParUnion<'a, T, S, A> { + ParUnion { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the difference, + /// i.e. the values that are in `self` but not in `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_difference<'a>(&'a self, other: &'a Self) -> ParDifference<'a, T, S, A> { + ParDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the symmetric + /// difference, i.e. the values that are in `self` or in `other` but not in both. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_symmetric_difference<'a>( + &'a self, + other: &'a Self, + ) -> ParSymmetricDifference<'a, T, S, A> { + ParSymmetricDifference { a: self, b: other } + } + + /// Visits (potentially in parallel) the values representing the + /// intersection, i.e. the values that are both in `self` and `other`. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_intersection<'a>(&'a self, other: &'a Self) -> ParIntersection<'a, T, S, A> { + ParIntersection { a: self, b: other } + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_disjoint(&self, other: &Self) -> bool { + self.into_par_iter().all(|x| !other.contains(x)) + } + + /// Returns `true` if the set is a subset of another, + /// i.e. `other` contains at least all the values in `self`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_subset(&self, other: &Self) -> bool { + if self.len() <= other.len() { + self.into_par_iter().all(|x| other.contains(x)) + } else { + false + } + } + + /// Returns `true` if the set is a superset of another, + /// i.e. `self` contains at least all the values in `other`. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_is_superset(&self, other: &Self) -> bool { + other.par_is_subset(self) + } + + /// Returns `true` if the set is equal to another, + /// i.e. both sets contain the same values. + /// + /// This method runs in a potentially parallel fashion. + pub fn par_eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.par_is_subset(other) + } +} + +impl HashSet +where + T: Eq + Hash + Send, + A: Allocator + Send, +{ + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the set's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.map.par_drain(), + } + } +} + +impl IntoParallelIterator for HashSet { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.map.into_par_iter(), + } + } +} + +impl<'a, T: Sync, S, A: Allocator> IntoParallelIterator for &'a HashSet { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: self.map.par_keys(), + } + } +} + +/// Collect values from a parallel iterator into a hashset. +impl FromParallelIterator for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher + Default, +{ + fn from_par_iter

(par_iter: P) -> Self + where + P: IntoParallelIterator, + { + let mut set = HashSet::default(); + set.par_extend(par_iter); + set + } +} + +/// Extend a hash set with items from a parallel iterator. +impl ParallelExtend for HashSet +where + T: Eq + Hash + Send, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +/// Extend a hash set with copied items from a parallel iterator. +impl<'a, T, S> ParallelExtend<&'a T> for HashSet +where + T: 'a + Copy + Eq + Hash + Sync, + S: BuildHasher, +{ + fn par_extend(&mut self, par_iter: I) + where + I: IntoParallelIterator, + { + extend(self, par_iter); + } +} + +// This is equal to the normal `HashSet` -- no custom advantage. +fn extend(set: &mut HashSet, par_iter: I) +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, + I: IntoParallelIterator, + HashSet: Extend, +{ + let (list, len) = super::helpers::collect(par_iter); + + // Values may be already present or show multiple times in the iterator. + // Reserve the entire length if the set is empty. + // Otherwise reserve half the length (rounded up), so the set + // will only resize twice in the worst case. + let reserve = if set.is_empty() { len } else { (len + 1) / 2 }; + set.reserve(reserve); + for vec in list { + set.extend(vec); + } +} + +#[cfg(test)] +mod test_par_set { + use alloc::vec::Vec; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::hash_set::HashSet; + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.par_is_disjoint(&ys)); + assert!(ys.par_is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.par_is_disjoint(&ys)); + assert!(!ys.par_is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(!b.par_is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.par_is_subset(&b)); + assert!(!a.par_is_superset(&b)); + assert!(!b.par_is_subset(&a)); + assert!(b.par_is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let expected = [3, 5, 11, 77]; + let i = a + .par_intersection(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let expected = [1, 5, 11]; + let i = a + .par_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let expected = [-2, 1, 5, 11, 14, 22]; + let i = a + .par_symmetric_difference(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + let i = a + .par_union(&b) + .map(|x| { + assert!(expected.contains(x)); + 1 + }) + .sum::(); + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.par_iter().cloned().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(!s1.par_eq(&s2)); + + s2.insert(3); + + assert!(s1.par_eq(&s2)); + } + + #[test] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.par_extend(&[2, 3, 4][..]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.par_extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs new file mode 100644 index 0000000..e8e5094 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rayon/table.rs @@ -0,0 +1,252 @@ +//! Rayon extensions for `HashTable`. + +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; +use crate::hash_table::HashTable; +use crate::raw::{Allocator, Global}; +use core::fmt; +use core::marker::PhantomData; +use rayon::iter::plumbing::UnindexedConsumer; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; + +/// Parallel iterator over shared references to entries in a map. +/// +/// This iterator is created by the [`par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter`]: /hashbrown/struct.HashTable.html#method.par_iter +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html +pub struct ParIter<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a T>, +} + +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_ref() }) + .drive_unindexed(consumer) + } +} + +impl Clone for ParIter<'_, T> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for ParIter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { x.as_ref() }); + f.debug_list().entries(iter).finish() + } +} + +/// Parallel iterator over mutable references to entries in a map. +/// +/// This iterator is created by the [`par_iter_mut`] method on [`HashTable`] +/// (provided by the [`IntoParallelRefMutIterator`] trait). +/// See its documentation for more. +/// +/// [`par_iter_mut`]: /hashbrown/struct.HashTable.html#method.par_iter_mut +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html +pub struct ParIterMut<'a, T> { + inner: RawParIter, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T: Send> ParallelIterator for ParIterMut<'a, T> { + type Item = &'a mut T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner + .map(|x| unsafe { x.as_mut() }) + .drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParIterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel iterator over entries of a consumed map. +/// +/// This iterator is created by the [`into_par_iter`] method on [`HashTable`] +/// (provided by the [`IntoParallelIterator`] trait). +/// See its documentation for more. +/// +/// [`into_par_iter`]: /hashbrown/struct.HashTable.html#method.into_par_iter +/// [`HashTable`]: /hashbrown/struct.HashTable.html +/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html +pub struct IntoParIter { + inner: RawIntoParIter, +} + +impl ParallelIterator for IntoParIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +/// Parallel draining iterator over entries of a map. +/// +/// This iterator is created by the [`par_drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`par_drain`]: /hashbrown/struct.HashTable.html#method.par_drain +/// [`HashTable`]: /hashbrown/struct.HashTable.html +pub struct ParDrain<'a, T, A: Allocator = Global> { + inner: RawParDrain<'a, T, A>, +} + +impl ParallelIterator for ParDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + self.inner.drive_unindexed(consumer) + } +} + +impl fmt::Debug for ParDrain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) + } +} + +impl HashTable { + /// Consumes (potentially in parallel) all values in an arbitrary order, + /// while preserving the map's allocated memory for reuse. + #[cfg_attr(feature = "inline-more", inline)] + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.raw.par_drain(), + } + } +} + +impl IntoParallelIterator for HashTable { + type Item = T; + type Iter = IntoParIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + IntoParIter { + inner: self.raw.into_par_iter(), + } + } +} + +impl<'a, T: Sync, A: Allocator> IntoParallelIterator for &'a HashTable { + type Item = &'a T; + type Iter = ParIter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIter { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +impl<'a, T: Send, A: Allocator> IntoParallelIterator for &'a mut HashTable { + type Item = &'a mut T; + type Iter = ParIterMut<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_par_iter(self) -> Self::Iter { + ParIterMut { + inner: unsafe { self.raw.par_iter() }, + marker: PhantomData, + } + } +} + +#[cfg(test)] +mod test_par_table { + use alloc::vec::Vec; + use core::sync::atomic::{AtomicUsize, Ordering}; + + use rayon::prelude::*; + + use crate::{ + hash_map::{make_hash, DefaultHashBuilder}, + hash_table::HashTable, + }; + + #[test] + fn test_iterate() { + let hasher = DefaultHashBuilder::default(); + let mut a = HashTable::new(); + for i in 0..32 { + a.insert_unique(make_hash(&hasher, &i), i, |x| make_hash(&hasher, x)); + } + let observed = AtomicUsize::new(0); + a.par_iter().for_each(|k| { + observed.fetch_or(1 << *k, Ordering::Relaxed); + }); + assert_eq!(observed.into_inner(), 0xFFFF_FFFF); + } + + #[test] + fn test_move_iter() { + let hasher = DefaultHashBuilder::default(); + let hs = { + let mut hs = HashTable::new(); + + hs.insert_unique(make_hash(&hasher, &'a'), 'a', |x| make_hash(&hasher, x)); + hs.insert_unique(make_hash(&hasher, &'b'), 'b', |x| make_hash(&hasher, x)); + + hs + }; + + let v = hs.into_par_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs new file mode 100644 index 0000000..fae7f76 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_map.rs @@ -0,0 +1,125 @@ +use crate::HashMap; +use core::{ + borrow::Borrow, + hash::{BuildHasher, Hash}, +}; +use rkyv::{ + collections::hash_map::{ArchivedHashMap, HashMapResolver}, + ser::{ScratchSpace, Serializer}, + Archive, Deserialize, Fallible, Serialize, +}; + +impl Archive for HashMap +where + K::Archived: Hash + Eq, +{ + type Archived = ArchivedHashMap; + type Resolver = HashMapResolver; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + ArchivedHashMap::resolve_from_len(self.len(), pos, resolver, out); + } +} + +impl Serialize for HashMap +where + K: Serialize + Hash + Eq, + K::Archived: Hash + Eq, + V: Serialize, + S: Serializer + ScratchSpace + ?Sized, +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + unsafe { ArchivedHashMap::serialize_from_iter(self.iter(), serializer) } + } +} + +impl + Deserialize, D> for ArchivedHashMap +where + K::Archived: Deserialize + Hash + Eq, + V::Archived: Deserialize, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + let mut result = HashMap::with_capacity_and_hasher(self.len(), S::default()); + for (k, v) in self.iter() { + result.insert(k.deserialize(deserializer)?, v.deserialize(deserializer)?); + } + Ok(result) + } +} + +impl, V, AK: Hash + Eq, AV: PartialEq, S: BuildHasher> + PartialEq> for ArchivedHashMap +{ + #[inline] + fn eq(&self, other: &HashMap) -> bool { + if self.len() != other.len() { + false + } else { + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| value.eq(v))) + } + } +} + +impl, V, AK: Hash + Eq, AV: PartialEq> + PartialEq> for HashMap +{ + #[inline] + fn eq(&self, other: &ArchivedHashMap) -> bool { + other.eq(self) + } +} + +#[cfg(test)] +mod tests { + use crate::HashMap; + use alloc::string::String; + use rkyv::{ + archived_root, check_archived_root, + ser::{serializers::AllocSerializer, Serializer}, + Deserialize, Infallible, + }; + + #[test] + fn index_map() { + let mut value = HashMap::new(); + value.insert(String::from("foo"), 10); + value.insert(String::from("bar"), 20); + value.insert(String::from("baz"), 40); + value.insert(String::from("bat"), 80); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + let archived = unsafe { archived_root::>(result.as_ref()) }; + + assert_eq!(value.len(), archived.len()); + for (k, v) in value.iter() { + let (ak, av) = archived.get_key_value(k.as_str()).unwrap(); + assert_eq!(k, ak); + assert_eq!(v, av); + } + + let deserialized: HashMap = archived.deserialize(&mut Infallible).unwrap(); + assert_eq!(value, deserialized); + } + + #[test] + fn validate_index_map() { + let mut value = HashMap::new(); + value.insert(String::from("foo"), 10); + value.insert(String::from("bar"), 20); + value.insert(String::from("baz"), 40); + value.insert(String::from("bat"), 80); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + check_archived_root::>(result.as_ref()) + .expect("failed to validate archived index map"); + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs new file mode 100644 index 0000000..c8a69cf --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/hash_set.rs @@ -0,0 +1,123 @@ +use crate::HashSet; +use core::{ + borrow::Borrow, + hash::{BuildHasher, Hash}, +}; +use rkyv::{ + collections::hash_set::{ArchivedHashSet, HashSetResolver}, + ser::{ScratchSpace, Serializer}, + Archive, Deserialize, Fallible, Serialize, +}; + +impl Archive for HashSet +where + K::Archived: Hash + Eq, +{ + type Archived = ArchivedHashSet; + type Resolver = HashSetResolver; + + #[inline] + unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) { + ArchivedHashSet::::resolve_from_len(self.len(), pos, resolver, out); + } +} + +impl Serialize for HashSet +where + K::Archived: Hash + Eq, + K: Serialize + Hash + Eq, + S: ScratchSpace + Serializer + ?Sized, +{ + #[inline] + fn serialize(&self, serializer: &mut S) -> Result { + unsafe { ArchivedHashSet::serialize_from_iter(self.iter(), serializer) } + } +} + +impl Deserialize, D> for ArchivedHashSet +where + K: Archive + Hash + Eq, + K::Archived: Deserialize + Hash + Eq, + D: Fallible + ?Sized, + S: Default + BuildHasher, +{ + #[inline] + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + let mut result = HashSet::with_hasher(S::default()); + for k in self.iter() { + result.insert(k.deserialize(deserializer)?); + } + Ok(result) + } +} + +impl, AK: Hash + Eq, S: BuildHasher> PartialEq> + for ArchivedHashSet +{ + #[inline] + fn eq(&self, other: &HashSet) -> bool { + if self.len() != other.len() { + false + } else { + self.iter().all(|key| other.get(key).is_some()) + } + } +} + +impl, AK: Hash + Eq, S: BuildHasher> PartialEq> + for HashSet +{ + #[inline] + fn eq(&self, other: &ArchivedHashSet) -> bool { + other.eq(self) + } +} + +#[cfg(test)] +mod tests { + use crate::HashSet; + use alloc::string::String; + use rkyv::{ + archived_root, check_archived_root, + ser::{serializers::AllocSerializer, Serializer}, + Deserialize, Infallible, + }; + + #[test] + fn index_set() { + let mut value = HashSet::new(); + value.insert(String::from("foo")); + value.insert(String::from("bar")); + value.insert(String::from("baz")); + value.insert(String::from("bat")); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + let archived = unsafe { archived_root::>(result.as_ref()) }; + + assert_eq!(value.len(), archived.len()); + for k in value.iter() { + let ak = archived.get(k.as_str()).unwrap(); + assert_eq!(k, ak); + } + + let deserialized: HashSet = archived.deserialize(&mut Infallible).unwrap(); + assert_eq!(value, deserialized); + } + + #[test] + fn validate_index_set() { + let mut value = HashSet::new(); + value.insert(String::from("foo")); + value.insert(String::from("bar")); + value.insert(String::from("baz")); + value.insert(String::from("bat")); + + let mut serializer = AllocSerializer::<4096>::default(); + serializer.serialize_value(&value).unwrap(); + let result = serializer.into_serializer().into_inner(); + check_archived_root::>(result.as_ref()) + .expect("failed to validate archived index set"); + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs new file mode 100644 index 0000000..2bde6a0 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/rkyv/mod.rs @@ -0,0 +1,2 @@ +mod hash_map; +mod hash_set; diff --git a/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/serde.rs b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/serde.rs new file mode 100644 index 0000000..0a76dbe --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/external_trait_impls/serde.rs @@ -0,0 +1,220 @@ +mod size_hint { + use core::cmp; + + /// This presumably exists to prevent denial of service attacks. + /// + /// Original discussion: https://github.com/serde-rs/serde/issues/1114. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn cautious(hint: Option) -> usize { + cmp::min(hint.unwrap_or(0), 4096) + } +} + +mod map { + use crate::raw::Allocator; + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde::de::{Deserialize, Deserializer, MapAccess, Visitor}; + use serde::ser::{Serialize, Serializer}; + + use crate::hash_map::HashMap; + + use super::size_hint; + + impl Serialize for HashMap + where + K: Serialize + Eq + Hash, + V: Serialize, + H: BuildHasher, + A: Allocator, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_map(self) + } + } + + impl<'de, K, V, S, A> Deserialize<'de> for HashMap + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + A: Allocator + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct MapVisitor + where + A: Allocator, + { + marker: PhantomData>, + } + + impl<'de, K, V, S, A> Visitor<'de> for MapVisitor + where + K: Deserialize<'de> + Eq + Hash, + V: Deserialize<'de>, + S: BuildHasher + Default, + A: Allocator + Default, + { + type Value = HashMap; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_map(self, mut map: M) -> Result + where + M: MapAccess<'de>, + { + let mut values = HashMap::with_capacity_and_hasher_in( + size_hint::cautious(map.size_hint()), + S::default(), + A::default(), + ); + + while let Some((key, value)) = map.next_entry()? { + values.insert(key, value); + } + + Ok(values) + } + } + + let visitor = MapVisitor { + marker: PhantomData, + }; + deserializer.deserialize_map(visitor) + } + } +} + +mod set { + use crate::raw::Allocator; + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; + use serde::ser::{Serialize, Serializer}; + + use crate::hash_set::HashSet; + + use super::size_hint; + + impl Serialize for HashSet + where + T: Serialize + Eq + Hash, + H: BuildHasher, + A: Allocator, + { + #[cfg_attr(feature = "inline-more", inline)] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } + } + + impl<'de, T, S, A> Deserialize<'de> for HashSet + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator + Default, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct SeqVisitor + where + A: Allocator, + { + marker: PhantomData>, + } + + impl<'de, T, S, A> Visitor<'de> for SeqVisitor + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator + Default, + { + type Value = HashSet; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: M) -> Result + where + M: SeqAccess<'de>, + { + let mut values = HashSet::with_capacity_and_hasher_in( + size_hint::cautious(seq.size_hint()), + S::default(), + A::default(), + ); + + while let Some(value) = seq.next_element()? { + values.insert(value); + } + + Ok(values) + } + } + + let visitor = SeqVisitor { + marker: PhantomData, + }; + deserializer.deserialize_seq(visitor) + } + + #[allow(clippy::missing_errors_doc)] + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct SeqInPlaceVisitor<'a, T, S, A>(&'a mut HashSet) + where + A: Allocator; + + impl<'a, 'de, T, S, A> Visitor<'de> for SeqInPlaceVisitor<'a, T, S, A> + where + T: Deserialize<'de> + Eq + Hash, + S: BuildHasher + Default, + A: Allocator, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a sequence") + } + + #[cfg_attr(feature = "inline-more", inline)] + fn visit_seq(self, mut seq: M) -> Result + where + M: SeqAccess<'de>, + { + self.0.clear(); + self.0.reserve(size_hint::cautious(seq.size_hint())); + + while let Some(value) = seq.next_element()? { + self.0.insert(value); + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqInPlaceVisitor(place)) + } + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/lib.rs b/third_party/crates/hashbrown-0.14.5/src/lib.rs new file mode 100644 index 0000000..f03ddb6 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/lib.rs @@ -0,0 +1,188 @@ +//! This crate is a Rust port of Google's high-performance [SwissTable] hash +//! map, adapted to make it a drop-in replacement for Rust's standard `HashMap` +//! and `HashSet` types. +//! +//! The original C++ version of [SwissTable] can be found [here], and this +//! [CppCon talk] gives an overview of how the algorithm works. +//! +//! [SwissTable]: https://abseil.io/blog/20180927-swisstables +//! [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h +//! [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4 + +#![no_std] +#![cfg_attr( + feature = "nightly", + feature( + test, + core_intrinsics, + dropck_eyepatch, + min_specialization, + extend_one, + allocator_api, + slice_ptr_get, + maybe_uninit_array_assume_init, + strict_provenance + ) +)] +#![allow( + clippy::doc_markdown, + clippy::module_name_repetitions, + clippy::must_use_candidate, + clippy::option_if_let_else, + clippy::redundant_else, + clippy::manual_map, + clippy::missing_safety_doc, + clippy::missing_errors_doc +)] +#![warn(missing_docs)] +#![warn(rust_2018_idioms)] +#![cfg_attr(feature = "nightly", warn(fuzzy_provenance_casts))] +#![cfg_attr(feature = "nightly", allow(internal_features))] + +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg_attr(test, macro_use)] +extern crate alloc; + +#[cfg(feature = "nightly")] +#[cfg(doctest)] +doc_comment::doctest!("../README.md"); + +#[macro_use] +mod macros; + +#[cfg(feature = "raw")] +/// Experimental and unsafe `RawTable` API. This module is only available if the +/// `raw` feature is enabled. +pub mod raw { + // The RawTable API is still experimental and is not properly documented yet. + #[allow(missing_docs)] + #[path = "mod.rs"] + mod inner; + pub use inner::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash maps. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::raw::*; + } +} +#[cfg(not(feature = "raw"))] +mod raw; + +mod external_trait_impls; +mod map; +#[cfg(feature = "rustc-internal-api")] +mod rustc_entry; +mod scopeguard; +mod set; +mod table; + +pub mod hash_map { + //! A hash map implemented with quadratic probing and SIMD lookup. + pub use crate::map::*; + + #[cfg(feature = "rustc-internal-api")] + pub use crate::rustc_entry::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash maps. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::map::*; + } +} +pub mod hash_set { + //! A hash set implemented as a `HashMap` where the value is `()`. + pub use crate::set::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash sets. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::set::*; + } +} +pub mod hash_table { + //! A hash table implemented with quadratic probing and SIMD lookup. + pub use crate::table::*; + + #[cfg(feature = "rayon")] + /// [rayon]-based parallel iterator types for hash tables. + /// You will rarely need to interact with it directly unless you have need + /// to name one of the iterator types. + /// + /// [rayon]: https://docs.rs/rayon/1.0/rayon + pub mod rayon { + pub use crate::external_trait_impls::rayon::table::*; + } +} + +pub use crate::map::HashMap; +pub use crate::set::HashSet; +pub use crate::table::HashTable; + +#[cfg(feature = "equivalent")] +pub use equivalent::Equivalent; + +// This is only used as a fallback when building as part of `std`. +#[cfg(not(feature = "equivalent"))] +/// Key equivalence trait. +/// +/// This trait defines the function used to compare the input value with the +/// map keys (or set values) during a lookup operation such as [`HashMap::get`] +/// or [`HashSet::contains`]. +/// It is provided with a blanket implementation based on the +/// [`Borrow`](core::borrow::Borrow) trait. +/// +/// # Correctness +/// +/// Equivalent values must hash to the same value. +pub trait Equivalent { + /// Checks if this value is equivalent to the given key. + /// + /// Returns `true` if both values are equivalent, and `false` otherwise. + /// + /// # Correctness + /// + /// When this function returns `true`, both `self` and `key` must hash to + /// the same value. + fn equivalent(&self, key: &K) -> bool; +} + +#[cfg(not(feature = "equivalent"))] +impl Equivalent for Q +where + Q: Eq, + K: core::borrow::Borrow, +{ + fn equivalent(&self, key: &K) -> bool { + self == key.borrow() + } +} + +/// The error type for `try_reserve` methods. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum TryReserveError { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + + /// The memory allocator returned an error + AllocError { + /// The layout of the allocation request that failed. + layout: alloc::alloc::Layout, + }, +} diff --git a/third_party/crates/hashbrown-0.14.5/src/macros.rs b/third_party/crates/hashbrown-0.14.5/src/macros.rs new file mode 100644 index 0000000..eaba6be --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/macros.rs @@ -0,0 +1,70 @@ +// See the cfg-if crate. +#[allow(unused_macro_rules)] +macro_rules! cfg_if { + // match if/else chains with a final `else` + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + cfg_if! { + @__items + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + + // match if/else chains lacking a final `else` + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + cfg_if! { + @__items + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + }; + + // Internal and recursive macro to emit all the items + // + // Collects all the negated cfgs in a list at the beginning and after the + // semicolon is all the remaining items + (@__items ($($not:meta,)*) ; ) => {}; + (@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + // Emit all items within one block, applying an appropriate #[cfg]. The + // #[cfg] will require all `$m` matchers specified and must also negate + // all previous matchers. + cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } + + // Recurse to emit all other items in `$rest`, and when we do so add all + // our `$m` matchers to the list of `$not` matchers as future emissions + // will have to negate everything we just matched as well. + cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } + }; + + // Internal macro to Apply a cfg attribute to a list of items + (@__apply $m:meta, $($it:item)*) => { + $(#[$m] $it)* + }; +} + +// Helper macro for specialization. This also helps avoid parse errors if the +// default fn syntax for specialization changes in the future. +#[cfg(feature = "nightly")] +macro_rules! default_fn { + (#[$($a:tt)*] $($tt:tt)*) => { + #[$($a)*] default $($tt)* + } +} +#[cfg(not(feature = "nightly"))] +macro_rules! default_fn { + ($($tt:tt)*) => { + $($tt)* + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/map.rs b/third_party/crates/hashbrown-0.14.5/src/map.rs new file mode 100644 index 0000000..88a8265 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/map.rs @@ -0,0 +1,8960 @@ +use crate::raw::{ + Allocator, Bucket, Global, RawDrain, RawExtractIf, RawIntoIter, RawIter, RawTable, +}; +use crate::{Equivalent, TryReserveError}; +use core::borrow::Borrow; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::ops::Index; + +/// Default hasher for `HashMap`. +#[cfg(feature = "ahash")] +pub type DefaultHashBuilder = core::hash::BuildHasherDefault; + +/// Dummy default hasher for `HashMap`. +#[cfg(not(feature = "ahash"))] +pub enum DefaultHashBuilder {} + +/// A hash map implemented with quadratic probing and SIMD lookup. +/// +/// The default hashing algorithm is currently [`AHash`], though this is +/// subject to change at any point in the future. This hash function is very +/// fast for all types of keys, but this algorithm will typically *not* protect +/// against attacks such as HashDoS. +/// +/// The hashing algorithm can be replaced on a per-`HashMap` basis using the +/// [`default`], [`with_hasher`], and [`with_capacity_and_hasher`] methods. Many +/// alternative algorithms are available on crates.io, such as the [`fnv`] crate. +/// +/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although +/// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. +/// If you implement these yourself, it is important that the following +/// property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// It is a logic error for a key to be modified in such a way that the key's +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashMap` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashMap` in this example). +/// let mut book_reviews = HashMap::new(); +/// +/// // Review some books. +/// book_reviews.insert( +/// "Adventures of Huckleberry Finn".to_string(), +/// "My favorite book.".to_string(), +/// ); +/// book_reviews.insert( +/// "Grimms' Fairy Tales".to_string(), +/// "Masterpiece.".to_string(), +/// ); +/// book_reviews.insert( +/// "Pride and Prejudice".to_string(), +/// "Very enjoyable.".to_string(), +/// ); +/// book_reviews.insert( +/// "The Adventures of Sherlock Holmes".to_string(), +/// "Eye lyked it alot.".to_string(), +/// ); +/// +/// // Check for a specific one. +/// // When collections store owned values (String), they can still be +/// // queried using references (&str). +/// if !book_reviews.contains_key("Les Misérables") { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// book_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// book_reviews.remove("The Adventures of Sherlock Holmes"); +/// +/// // Look up the values associated with some keys. +/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; +/// for &book in &to_find { +/// match book_reviews.get(book) { +/// Some(review) => println!("{}: {}", book, review), +/// None => println!("{} is unreviewed.", book) +/// } +/// } +/// +/// // Look up the value for a key (will panic if the key is not found). +/// println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]); +/// +/// // Iterate over everything. +/// for (book, review) in &book_reviews { +/// println!("{}: \"{}\"", book, review); +/// } +/// ``` +/// +/// `HashMap` also implements an [`Entry API`](#method.entry), which allows +/// for more complex methods of getting, setting, updating and removing keys and +/// their values: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `HashMap<&str, u8>` in this example). +/// let mut player_stats = HashMap::new(); +/// +/// fn random_stat_buff() -> u8 { +/// // could actually return some random value here - let's just return +/// // some fixed value for now +/// 42 +/// } +/// +/// // insert a key only if it doesn't already exist +/// player_stats.entry("health").or_insert(100); +/// +/// // insert a key using a function that provides a new value only if it +/// // doesn't already exist +/// player_stats.entry("defence").or_insert_with(random_stat_buff); +/// +/// // update a key, guarding against the key possibly not being set +/// let stat = player_stats.entry("attack").or_insert(100); +/// *stat += random_stat_buff(); +/// ``` +/// +/// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. +/// We must also derive [`PartialEq`]. +/// +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html +/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +/// [`default`]: #method.default +/// [`with_hasher`]: #method.with_hasher +/// [`with_capacity_and_hasher`]: #method.with_capacity_and_hasher +/// [`fnv`]: https://crates.io/crates/fnv +/// [`AHash`]: https://crates.io/crates/ahash +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// country: String, +/// } +/// +/// impl Viking { +/// /// Creates a new Viking. +/// fn new(name: &str, country: &str) -> Viking { +/// Viking { name: name.to_string(), country: country.to_string() } +/// } +/// } +/// +/// // Use a HashMap to store the vikings' health points. +/// let mut vikings = HashMap::new(); +/// +/// vikings.insert(Viking::new("Einar", "Norway"), 25); +/// vikings.insert(Viking::new("Olaf", "Denmark"), 24); +/// vikings.insert(Viking::new("Harald", "Iceland"), 12); +/// +/// // Use derived implementation to print the status of the vikings. +/// for (viking, health) in &vikings { +/// println!("{:?} has {} hp", viking, health); +/// } +/// ``` +/// +/// A `HashMap` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] +/// .into_iter().collect(); +/// // use the values stored in map +/// ``` +pub struct HashMap { + pub(crate) hash_builder: S, + pub(crate) table: RawTable<(K, V), A>, +} + +impl Clone for HashMap { + fn clone(&self) -> Self { + HashMap { + hash_builder: self.hash_builder.clone(), + table: self.table.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.table.clone_from(&source.table); + + // Update hash_builder only if we successfully cloned all elements. + self.hash_builder.clone_from(&source.hash_builder); + } +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like RawTable::reserve from being generated +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hasher(hash_builder: &S) -> impl Fn(&(Q, V)) -> u64 + '_ +where + Q: Hash, + S: BuildHasher, +{ + move |val| make_hash::(hash_builder, &val.0) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like RawTable::reserve from being generated +#[cfg_attr(feature = "inline-more", inline)] +fn equivalent_key(k: &Q) -> impl Fn(&(K, V)) -> bool + '_ +where + Q: ?Sized + Equivalent, +{ + move |x| k.equivalent(&x.0) +} + +/// Ensures that a single closure type across uses of this which, in turn prevents multiple +/// instances of any functions like RawTable::reserve from being generated +#[cfg_attr(feature = "inline-more", inline)] +fn equivalent(k: &Q) -> impl Fn(&K) -> bool + '_ +where + Q: ?Sized + Equivalent, +{ + move |x| k.equivalent(x) +} + +#[cfg(not(feature = "nightly"))] +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +where + Q: Hash + ?Sized, + S: BuildHasher, +{ + use core::hash::Hasher; + let mut state = hash_builder.build_hasher(); + val.hash(&mut state); + state.finish() +} + +#[cfg(feature = "nightly")] +#[cfg_attr(feature = "inline-more", inline)] +pub(crate) fn make_hash(hash_builder: &S, val: &Q) -> u64 +where + Q: Hash + ?Sized, + S: BuildHasher, +{ + hash_builder.hash_one(val) +} + +#[cfg(feature = "ahash")] +impl HashMap { + /// Creates an empty `HashMap`. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher`](HashMap::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// assert_eq!(map.len(), 0); + /// assert_eq!(map.capacity(), 0); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self::default() + } + + /// Creates an empty `HashMap` with the specified capacity. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher`](HashMap::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_and_hasher(capacity, DefaultHashBuilder::default()) + } +} + +#[cfg(feature = "ahash")] +impl HashMap { + /// Creates an empty `HashMap` using the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_hasher_in`](HashMap::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::new_in(&bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// + /// // The created HashMap also doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// // Now we insert element inside created HashMap + /// map.insert("One", 1); + /// // We can see that the HashMap holds 1 element + /// assert_eq!(map.len(), 1); + /// // And it also allocates some capacity + /// assert!(map.capacity() > 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self::with_hasher_in(DefaultHashBuilder::default(), alloc) + } + + /// Creates an empty `HashMap` with the specified capacity using the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`], for example with + /// [`with_capacity_and_hasher_in`](HashMap::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use bumpalo::Bump; + /// + /// let bump = Bump::new(); + /// let mut map = HashMap::with_capacity_in(5, &bump); + /// + /// // The created HashMap holds none elements + /// assert_eq!(map.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = map.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashMap + /// map.insert("One", 1); + /// map.insert("Two", 2); + /// map.insert("Three", 3); + /// map.insert("Four", 4); + /// map.insert("Five", 5); + /// + /// // We can see that the HashMap holds 5 elements + /// assert_eq!(map.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(map.capacity(), empty_map_capacity) + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self::with_capacity_and_hasher_in(capacity, DefaultHashBuilder::default(), alloc) + } +} + +impl HashMap { + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. + /// + /// The hash map is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// assert_eq!(map.len(), 0); + /// assert_eq!(map.capacity(), 0); + /// + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher(hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::new(), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 10); + /// + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity(capacity), + } + } +} + +impl HashMap { + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + self.table.allocator() + } + + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. It will be allocated with the given allocator. + /// + /// The hash map is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher_in(hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. It will be allocated with the given allocator. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashMap` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashMap`]. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { + Self { + hash_builder, + table: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the map's [`BuildHasher`]. + /// + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let map: HashMap = HashMap::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = map.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + &self.hash_builder + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the `HashMap` might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let map: HashMap = HashMap::with_capacity(100); + /// assert_eq!(map.len(), 0); + /// assert!(map.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.table.capacity() + } + + /// An iterator visiting all keys in arbitrary order. + /// The iterator element type is `&'a K`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<&str> = Vec::new(); + /// + /// for key in map.keys() { + /// println!("{}", key); + /// vec.push(*key); + /// } + /// + /// // The `Keys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn keys(&self) -> Keys<'_, K, V> { + Keys { inner: self.iter() } + } + + /// An iterator visiting all values in arbitrary order. + /// The iterator element type is `&'a V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in map.values() { + /// println!("{}", val); + /// vec.push(*val); + /// } + /// + /// // The `Values` iterator produces values in arbitrary order, so the + /// // values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values(&self) -> Values<'_, K, V> { + Values { inner: self.iter() } + } + + /// An iterator visiting all values mutably in arbitrary order. + /// The iterator element type is `&'a mut V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for val in map.values_mut() { + /// *val = *val + 10; + /// } + /// + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in map.values() { + /// println!("{}", val); + /// vec.push(*val); + /// } + /// + /// // The `Values` iterator produces values in arbitrary order, so the + /// // values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [11, 12, 13]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { + ValuesMut { + inner: self.iter_mut(), + } + } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<(&str, i32)> = Vec::new(); + /// + /// for (key, val) in map.iter() { + /// println!("key: {} val: {}", key, val); + /// vec.push((*key, *val)); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3)]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + Iter { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// The iterator element type is `(&'a K, &'a mut V)`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Update all values + /// for (_, val) in map.iter_mut() { + /// *val *= 2; + /// } + /// + /// assert_eq!(map.len(), 3); + /// let mut vec: Vec<(&str, i32)> = Vec::new(); + /// + /// for (key, val) in &map { + /// println!("key: {} val: {}", key, val); + /// vec.push((*key, *val)); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 2), ("b", 4), ("c", 6)]); + /// + /// assert_eq!(map.len(), 3); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + // Here we tie the lifetime of self to the iter. + unsafe { + IterMut { + inner: self.table.iter(), + marker: PhantomData, + } + } + } + + #[cfg(test)] + #[cfg_attr(feature = "inline-more", inline)] + fn raw_capacity(&self) -> usize { + self.table.buckets() + } + + /// Returns the number of elements in the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.table.len() + } + + /// Returns `true` if the map contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1, "a"); + /// assert!(!a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the map, returning all key-value pairs as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining key-value pairs. The returned iterator keeps a + /// mutable borrow on the vector to optimize its implementation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// let capacity_before_drain = a.capacity(); + /// + /// for (k, v) in a.drain().take(1) { + /// assert!(k == 1 || k == 2); + /// assert!(v == "a" || v == "b"); + /// } + /// + /// // As we can see, the map is empty and contains no element. + /// assert!(a.is_empty() && a.len() == 0); + /// // But map capacity is equal to old one. + /// assert_eq!(a.capacity(), capacity_before_drain); + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// + /// { // Iterator is dropped without being consumed. + /// let d = a.drain(); + /// } + /// + /// // But the map is empty even if we do not use Drain iterator. + /// assert!(a.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, K, V, A> { + Drain { + inner: self.table.drain(), + } + } + + /// Retains only the elements specified by the predicate. Keeps the + /// allocated memory for reuse. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// The elements are visited in unsorted (and unspecified) order. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); + /// assert_eq!(map.len(), 8); + /// + /// map.retain(|&k, _| k % 2 == 0); + /// + /// // We can see, that the number of elements inside map is changed. + /// assert_eq!(map.len(), 4); + /// + /// let mut vec: Vec<(i32, i32)> = map.iter().map(|(&k, &v)| (k, v)).collect(); + /// vec.sort_unstable(); + /// assert_eq!(vec, [(0, 0), (2, 20), (4, 40), (6, 60)]); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.table.iter() { + let &mut (ref key, ref mut value) = item.as_mut(); + if !f(key, value) { + self.table.erase(item); + } + } + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all pairs `(k, v)` such that `f(&k, &mut v)` returns `true` out + /// into another iterator. + /// + /// Note that `extract_if` lets you mutate every value in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// Keeps the allocated memory for reuse. + /// + /// [`retain()`]: HashMap::retain + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// + /// let drained: HashMap = map.extract_if(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().cloned().collect::>(); + /// let mut odds = map.keys().cloned().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// + /// { // Iterator is dropped without being consumed. + /// let d = map.extract_if(|k, _v| k % 2 != 0); + /// } + /// + /// // ExtractIf was not exhausted, therefore no elements were drained. + /// assert_eq!(map.len(), 8); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, K, V, F, A> + where + F: FnMut(&K, &mut V) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.table.iter() }, + table: &mut self.table, + }, + } + } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1, "a"); + /// let capacity_before_clear = a.capacity(); + /// + /// a.clear(); + /// + /// // Map is empty. + /// assert!(a.is_empty()); + /// // But map capacity is equal to old one. + /// assert_eq!(a.capacity(), capacity_before_clear); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.table.clear(); + } + + /// Creates a consuming iterator visiting all the keys in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `K`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let mut vec: Vec<&str> = map.into_keys().collect(); + /// + /// // The `IntoKeys` iterator produces keys in arbitrary order, so the + /// // keys must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, ["a", "b", "c"]); + /// ``` + #[inline] + pub fn into_keys(self) -> IntoKeys { + IntoKeys { + inner: self.into_iter(), + } + } + + /// Creates a consuming iterator visiting all the values in arbitrary order. + /// The map cannot be used after calling this. + /// The iterator element type is `V`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// let mut vec: Vec = map.into_values().collect(); + /// + /// // The `IntoValues` iterator produces values in arbitrary order, so + /// // the values must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[inline] + pub fn into_values(self) -> IntoValues { + IntoValues { + inner: self.into_iter(), + } + } +} + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashMap::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// // Map is empty and doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// map.reserve(10); + /// + /// // And now map can hold at least 10 elements + /// assert!(map.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.table + .reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// // Map is empty and doesn't allocate memory + /// assert_eq!(map.capacity(), 0); + /// + /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// + /// // And now map can hold at least 10 elements + /// assert!(map.capacity() >= 10); + /// ``` + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned: + /// ``` + /// # fn test() { + /// use hashbrown::HashMap; + /// use hashbrown::TryReserveError; + /// let mut map: HashMap = HashMap::new(); + /// + /// match map.try_reserve(usize::MAX) { + /// Err(error) => match error { + /// TryReserveError::CapacityOverflow => {} + /// _ => panic!("TryReserveError::AllocError ?"), + /// }, + /// _ => panic!(), + /// } + /// # } + /// # fn main() { + /// # #[cfg(not(miri))] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.table + .try_reserve(additional, make_hasher::<_, V, S>(&self.hash_builder)) + } + + /// Shrinks the capacity of the map as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to_fit(); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.table + .shrink_to(0, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Shrinks the capacity of the map with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// This function does nothing if the current capacity is smaller than the + /// supplied minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 10); + /// map.shrink_to(0); + /// assert!(map.capacity() >= 2); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.table + .shrink_to(min_capacity, make_hasher::<_, V, S>(&self.hash_builder)); + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S, A> { + let hash = make_hash::(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, equivalent_key(&key)) { + Entry::Occupied(OccupiedEntry { + hash, + key: Some(key), + elem, + table: self, + }) + } else { + Entry::Vacant(VacantEntry { + hash, + key, + table: self, + }) + } + } + + /// Gets the given key's corresponding entry by reference in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut words: HashMap = HashMap::new(); + /// let source = ["poneyland", "horseyland", "poneyland", "poneyland"]; + /// for (i, &s) in source.iter().enumerate() { + /// let counter = words.entry_ref(s).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(words["poneyland"], 3); + /// assert_eq!(words["horseyland"], 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry_ref<'a, 'b, Q: ?Sized>(&'a mut self, key: &'b Q) -> EntryRef<'a, 'b, K, Q, V, S, A> + where + Q: Hash + Equivalent, + { + let hash = make_hash::(&self.hash_builder, key); + if let Some(elem) = self.table.find(hash, equivalent_key(key)) { + EntryRef::Occupied(OccupiedEntryRef { + hash, + key: Some(KeyOrRef::Borrowed(key)), + elem, + table: self, + }) + } else { + EntryRef::Vacant(VacantEntryRef { + hash, + key: KeyOrRef::Borrowed(key), + table: self, + }) + } + } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[inline] + pub fn get(&self, k: &Q) -> Option<&V> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner(k) { + Some((_, v)) => Some(v), + None => None, + } + } + + /// Returns the key-value pair corresponding to the supplied key. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); + /// assert_eq!(map.get_key_value(&2), None); + /// ``` + #[inline] + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner(k) { + Some((key, value)) => Some((key, value)), + None => None, + } + } + + #[inline] + fn get_inner(&self, k: &Q) -> Option<&(K, V)> + where + Q: Hash + Equivalent, + { + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + self.table.get(hash, equivalent_key(k)) + } + } + + /// Returns the key-value pair corresponding to the supplied key, with a mutable reference to value. + /// + /// The supplied key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// let (k, v) = map.get_key_value_mut(&1).unwrap(); + /// assert_eq!(k, &1); + /// assert_eq!(v, &mut "a"); + /// *v = "b"; + /// assert_eq!(map.get_key_value_mut(&1), Some((&1, &mut "b"))); + /// assert_eq!(map.get_key_value_mut(&2), None); + /// ``` + #[inline] + pub fn get_key_value_mut(&mut self, k: &Q) -> Option<(&K, &mut V)> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner_mut(k) { + Some(&mut (ref key, ref mut value)) => Some((key, value)), + None => None, + } + } + + /// Returns `true` if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains_key(&self, k: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.get_inner(k).is_some() + } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, "a"); + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; + /// } + /// assert_eq!(map[&1], "b"); + /// + /// assert_eq!(map.get_mut(&2), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.get_inner_mut(k) { + Some(&mut (_, ref mut v)) => Some(v), + None => None, + } + } + + #[inline] + fn get_inner_mut(&mut self, k: &Q) -> Option<&mut (K, V)> + where + Q: Hash + Equivalent, + { + if self.table.is_empty() { + None + } else { + let hash = make_hash::(&self.hash_builder, k); + self.table.get_mut(hash, equivalent_key(k)) + } + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be returned if any of the + /// keys are duplicates or missing. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// &mut 1807, + /// &mut 1800, + /// ]), + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Athenæum", + /// ]); + /// assert_eq!(got, None); + /// ``` + pub fn get_many_mut(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]> + where + Q: Hash + Equivalent, + { + self.get_many_mut_inner(ks).map(|res| res.map(|(_, v)| v)) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_mut`](`HashMap::get_many_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// &mut 1807, + /// &mut 1800, + /// ]), + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!(got, None); + /// ``` + pub unsafe fn get_many_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> Option<[&'_ mut V; N]> + where + Q: Hash + Equivalent, + { + self.get_many_unchecked_mut_inner(ks) + .map(|res| res.map(|(_, v)| v)) + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be returned if any of the keys + /// are duplicates or missing. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// (&"Bodleian Library".to_string(), &mut 1602), + /// (&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691), + /// ]), + /// ); + /// // Missing keys result in None + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Gewandhaus", + /// ]); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!(got, None); + /// ``` + pub fn get_many_key_value_mut( + &mut self, + ks: [&Q; N], + ) -> Option<[(&'_ K, &'_ mut V); N]> + where + Q: Hash + Equivalent, + { + self.get_many_mut_inner(ks) + .map(|res| res.map(|(k, v)| (&*k, v))) + } + + /// Attempts to get mutable references to `N` values in the map at once, with immutable + /// references to the corresponding keys, without validating that the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_key_value_mut`](`HashMap::get_many_key_value_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Herzogin-Anna-Amalia-Bibliothek", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// (&"Bodleian Library".to_string(), &mut 1602), + /// (&"Herzogin-Anna-Amalia-Bibliothek".to_string(), &mut 1691), + /// ]), + /// ); + /// // Missing keys result in None + /// let got = libraries.get_many_key_value_mut([ + /// "Bodleian Library", + /// "Gewandhaus", + /// ]); + /// assert_eq!(got, None); + /// ``` + pub unsafe fn get_many_key_value_unchecked_mut( + &mut self, + ks: [&Q; N], + ) -> Option<[(&'_ K, &'_ mut V); N]> + where + Q: Hash + Equivalent, + { + self.get_many_unchecked_mut_inner(ks) + .map(|res| res.map(|(k, v)| (&*k, v))) + } + + fn get_many_mut_inner( + &mut self, + ks: [&Q; N], + ) -> Option<[&'_ mut (K, V); N]> + where + Q: Hash + Equivalent, + { + let hashes = self.build_hashes_inner(ks); + self.table + .get_many_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) + } + + unsafe fn get_many_unchecked_mut_inner( + &mut self, + ks: [&Q; N], + ) -> Option<[&'_ mut (K, V); N]> + where + Q: Hash + Equivalent, + { + let hashes = self.build_hashes_inner(ks); + self.table + .get_many_unchecked_mut(hashes, |i, (k, _)| ks[i].equivalent(k)) + } + + fn build_hashes_inner(&self, ks: [&Q; N]) -> [u64; N] + where + Q: Hash + Equivalent, + { + let mut hashes = [0_u64; N]; + for i in 0..N { + hashes[i] = make_hash::(&self.hash_builder, ks[i]); + } + hashes + } + + /// Inserts a key-value pair into the map. + /// + /// If the map did not have this key present, [`None`] is returned. + /// + /// If the map did have this key present, the value is updated, and the old + /// value is returned. The key is not updated, though; this matters for + /// types that can be `==` without being identical. See the [`std::collections`] + /// [module-level documentation] for more. + /// + /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + /// [`std::collections`]: https://doc.rust-lang.org/std/collections/index.html + /// [module-level documentation]: https://doc.rust-lang.org/std/collections/index.html#insert-and-complex-keys + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.insert(37, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[&37], "c"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, k: K, v: V) -> Option { + let hash = make_hash::(&self.hash_builder, &k); + let hasher = make_hasher::<_, V, S>(&self.hash_builder); + match self + .table + .find_or_find_insert_slot(hash, equivalent_key(&k), hasher) + { + Ok(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().1 }, v)), + Err(slot) => { + unsafe { + self.table.insert_in_slot(hash, slot, (k, v)); + } + None + } + } + } + + /// Insert a key-value pair into the map without checking + /// if the key already exists in the map. + /// + /// Returns a reference to the key and value just inserted. + /// + /// This operation is safe if a key does not exist in the map. + /// + /// However, if a key exists in the map already, the behavior is unspecified: + /// this operation may panic, loop forever, or any following operation with the map + /// may panic, loop forever or return arbitrary result. + /// + /// That said, this operation (and following operations) are guaranteed to + /// not violate memory safety. + /// + /// This operation is faster than regular insert, because it does not perform + /// lookup before insertion. + /// + /// This operation is useful during initial population of the map. + /// For example, when constructing a map from another map, we know + /// that keys are unique. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map1 = HashMap::new(); + /// assert_eq!(map1.insert(1, "a"), None); + /// assert_eq!(map1.insert(2, "b"), None); + /// assert_eq!(map1.insert(3, "c"), None); + /// assert_eq!(map1.len(), 3); + /// + /// let mut map2 = HashMap::new(); + /// + /// for (key, value) in map1.into_iter() { + /// map2.insert_unique_unchecked(key, value); + /// } + /// + /// let (key, value) = map2.insert_unique_unchecked(4, "d"); + /// assert_eq!(key, &4); + /// assert_eq!(value, &mut "d"); + /// *value = "e"; + /// + /// assert_eq!(map2[&1], "a"); + /// assert_eq!(map2[&2], "b"); + /// assert_eq!(map2[&3], "c"); + /// assert_eq!(map2[&4], "e"); + /// assert_eq!(map2.len(), 4); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) { + let hash = make_hash::(&self.hash_builder, &k); + let bucket = self + .table + .insert(hash, (k, v), make_hasher::<_, V, S>(&self.hash_builder)); + let (k_ref, v_ref) = unsafe { bucket.as_mut() }; + (k_ref, v_ref) + } + + /// Tries to insert a key-value pair into the map, and returns + /// a mutable reference to the value in the entry. + /// + /// # Errors + /// + /// If the map already had this key present, nothing is updated, and + /// an error containing the occupied entry and the value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::OccupiedError; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.try_insert(37, "a").unwrap(), &"a"); + /// + /// match map.try_insert(37, "b") { + /// Err(OccupiedError { entry, value }) => { + /// assert_eq!(entry.key(), &37); + /// assert_eq!(entry.get(), &"a"); + /// assert_eq!(value, "b"); + /// } + /// _ => panic!() + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_insert( + &mut self, + key: K, + value: V, + ) -> Result<&mut V, OccupiedError<'_, K, V, S, A>> { + match self.entry(key) { + Entry::Occupied(entry) => Err(OccupiedError { entry, value }), + Entry::Vacant(entry) => Ok(entry.insert(value)), + } + } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. Keeps the allocated memory for reuse. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.insert(1, "a"); + /// + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// + /// // Now map holds none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, k: &Q) -> Option + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.remove_entry(k) { + Some((_, v)) => Some(v), + None => None, + } + } + + /// Removes a key from the map, returning the stored key and value if the + /// key was previously in the map. Keeps the allocated memory for reuse. + /// + /// The key may be any borrowed form of the map's key type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the key type. + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.insert(1, "a"); + /// + /// assert_eq!(map.remove_entry(&1), Some((1, "a"))); + /// assert_eq!(map.remove(&1), None); + /// + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(&mut self, k: &Q) -> Option<(K, V)> + where + Q: Hash + Equivalent, + { + let hash = make_hash::(&self.hash_builder, k); + self.table.remove_entry(hash, equivalent_key(k)) + } +} + +impl HashMap { + /// Creates a raw entry builder for the HashMap. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. After this, insertions into a vacant entry + /// still require an owned key to be provided. + /// + /// Raw entries are useful for such exotic situations as: + /// + /// * Hash memoization + /// * Deferring the creation of an owned key until it is known to be required + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Because raw entries provide much more low-level control, it's much easier + /// to put the HashMap into an inconsistent state which, while memory-safe, + /// will cause the map to produce seemingly random results. Higher-level and + /// more foolproof APIs like `entry` should be preferred when possible. + /// + /// In particular, the hash used to initialized the raw entry must still be + /// consistent with the hash of the key that is ultimately stored in the entry. + /// This is because implementations of HashMap may need to recompute hashes + /// when resizing, at which point only the keys are available. + /// + /// Raw entries give mutable access to the keys. This must not be used + /// to modify how the key would compare or hash, as the map will not re-evaluate + /// where the key should go, meaning the keys may become "lost" if their + /// location does not reflect their state. For instance, if you change a key + /// so that the map now contains keys which compare equal, search may start + /// acting erratically, with two keys randomly masking each other. Implementations + /// are free to assume this doesn't happen (within the limits of memory-safety). + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// // Existing key (insert and update) + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(mut view) => { + /// assert_eq!(view.get(), &100); + /// let v = view.get_mut(); + /// let new_v = (*v) * 10; + /// *v = new_v; + /// assert_eq!(view.insert(1111), 1000); + /// } + /// } + /// + /// assert_eq!(map[&"a"], 1111); + /// assert_eq!(map.len(), 3); + /// + /// // Existing key (take) + /// let hash = compute_hash(map.hasher(), &"c"); + /// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"c") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.remove_entry(), ("c", 300)); + /// } + /// } + /// assert_eq!(map.raw_entry().from_key(&"c"), None); + /// assert_eq!(map.len(), 2); + /// + /// // Nonexistent key (insert and update) + /// let key = "d"; + /// let hash = compute_hash(map.hasher(), &key); + /// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(view) => { + /// let (k, value) = view.insert("d", 4000); + /// assert_eq!((*k, *value), ("d", 4000)); + /// *value = 40000; + /// } + /// } + /// assert_eq!(map[&"d"], 40000); + /// assert_eq!(map.len(), 3); + /// + /// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(view) => { + /// assert_eq!(view.remove_entry(), ("d", 40000)); + /// } + /// } + /// assert_eq!(map.get(&"d"), None); + /// assert_eq!(map.len(), 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S, A> { + RawEntryBuilderMut { map: self } + } + + /// Creates a raw immutable entry builder for the HashMap. + /// + /// Raw entries provide the lowest level of control for searching and + /// manipulating a map. They must be manually initialized with a hash and + /// then manually searched. + /// + /// This is useful for + /// * Hash memoization + /// * Using a search key that doesn't work with the Borrow trait + /// * Using custom comparison logic without newtype wrappers + /// + /// Unless you are in such a situation, higher-level and more foolproof APIs like + /// `get` should be preferred. + /// + /// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 100), ("b", 200), ("c", 300)]); + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// for k in ["a", "b", "c", "d", "e", "f"] { + /// let hash = compute_hash(map.hasher(), k); + /// let v = map.get(&k).cloned(); + /// let kv = v.as_ref().map(|v| (&k, v)); + /// + /// println!("Key: {} and value: {:?}", k, v); + /// + /// assert_eq!(map.raw_entry().from_key(&k), kv); + /// assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + /// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S, A> { + RawEntryBuilder { map: self } + } + + /// Returns a reference to the [`RawTable`] used underneath [`HashMap`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// See [`raw_table_mut`] for more. + /// + /// [`raw_table_mut`]: Self::raw_table_mut + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table(&self) -> &RawTable<(K, V), A> { + &self.table + } + + /// Returns a mutable reference to the [`RawTable`] used underneath [`HashMap`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// # Note + /// + /// Calling this function is safe, but using the raw hash table API may require + /// unsafe functions or blocks. + /// + /// `RawTable` API gives the lowest level of control under the map that can be useful + /// for extending the HashMap's API, but may lead to *[undefined behavior]*. + /// + /// [`HashMap`]: struct.HashMap.html + /// [`RawTable`]: crate::raw::RawTable + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.extend([("a", 10), ("b", 20), ("c", 30)]); + /// assert_eq!(map.len(), 3); + /// + /// // Let's imagine that we have a value and a hash of the key, but not the key itself. + /// // However, if you want to remove the value from the map by hash and value, and you + /// // know exactly that the value is unique, then you can create a function like this: + /// fn remove_by_hash( + /// map: &mut HashMap, + /// hash: u64, + /// is_match: F, + /// ) -> Option<(K, V)> + /// where + /// F: Fn(&(K, V)) -> bool, + /// { + /// let raw_table = map.raw_table_mut(); + /// match raw_table.find(hash, is_match) { + /// Some(bucket) => Some(unsafe { raw_table.remove(bucket).0 }), + /// None => None, + /// } + /// } + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash = compute_hash(map.hasher(), "a"); + /// assert_eq!(remove_by_hash(&mut map, hash, |(_, v)| *v == 10), Some(("a", 10))); + /// assert_eq!(map.get(&"a"), None); + /// assert_eq!(map.len(), 2); + /// ``` + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table_mut(&mut self) -> &mut RawTable<(K, V), A> { + &mut self.table + } +} + +impl PartialEq for HashMap +where + K: Eq + Hash, + V: PartialEq, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter() + .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) + } +} + +impl Eq for HashMap +where + K: Eq + Hash, + V: Eq, + S: BuildHasher, + A: Allocator, +{ +} + +impl Debug for HashMap +where + K: Debug, + V: Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_map().entries(self.iter()).finish() + } +} + +impl Default for HashMap +where + S: Default, + A: Default + Allocator, +{ + /// Creates an empty `HashMap`, with the `Default` value for the hasher and allocator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use std::collections::hash_map::RandomState; + /// + /// // You can specify all types of HashMap, including hasher and allocator. + /// // Created map is empty and don't allocate memory + /// let map: HashMap = Default::default(); + /// assert_eq!(map.capacity(), 0); + /// let map: HashMap = HashMap::default(); + /// assert_eq!(map.capacity(), 0); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self::with_hasher_in(Default::default(), Default::default()) + } +} + +impl Index<&Q> for HashMap +where + K: Eq + Hash, + Q: Hash + Equivalent, + S: BuildHasher, + A: Allocator, +{ + type Output = V; + + /// Returns a reference to the value corresponding to the supplied key. + /// + /// # Panics + /// + /// Panics if the key is not present in the `HashMap`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<_, _> = [("a", "One"), ("b", "Two")].into(); + /// + /// assert_eq!(map[&"a"], "One"); + /// assert_eq!(map[&"b"], "Two"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn index(&self, key: &Q) -> &V { + self.get(key).expect("no entry found for key") + } +} + +// The default hasher is used to match the std implementation signature +#[cfg(feature = "ahash")] +impl From<[(K, V); N]> for HashMap +where + K: Eq + Hash, + A: Default + Allocator, +{ + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map1 = HashMap::from([(1, 2), (3, 4)]); + /// let map2: HashMap<_, _> = [(1, 2), (3, 4)].into(); + /// assert_eq!(map1, map2); + /// ``` + fn from(arr: [(K, V); N]) -> Self { + arr.into_iter().collect() + } +} + +/// An iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(&'a K, &'a V)`. +/// +/// This `struct` is created by the [`iter`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashMap.html#method.iter +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut iter = map.iter(); +/// let mut vec = vec![iter.next(), iter.next(), iter.next()]; +/// +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((&1, &"a")), Some((&2, &"b")), Some((&3, &"c"))]); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// ``` +pub struct Iter<'a, K, V> { + inner: RawIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(&'a K, &'a mut V)`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashMap.html#method.iter_mut +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "One".to_owned()), (2, "Two".into())].into(); +/// +/// let mut iter = map.iter_mut(); +/// iter.next().map(|(_, v)| v.push_str(" Mississippi")); +/// iter.next().map(|(_, v)| v.push_str(" Mississippi")); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// +/// assert_eq!(map.get(&1).unwrap(), &"One Mississippi".to_owned()); +/// assert_eq!(map.get(&2).unwrap(), &"Two Mississippi".to_owned()); +/// ``` +pub struct IterMut<'a, K, V> { + inner: RawIter<(K, V)>, + // To ensure invariance with respect to V + marker: PhantomData<(&'a K, &'a mut V)>, +} + +// We override the default Send impl which has K: Sync instead of K: Send. Both +// are correct, but this one is more general since it allows keys which +// implement Send but not Sync. +unsafe impl Send for IterMut<'_, K, V> {} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + +/// An owning iterator over the entries of a `HashMap` in arbitrary order. +/// The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// The map cannot be used after calling that method. +/// +/// [`into_iter`]: struct.HashMap.html#method.into_iter +/// [`HashMap`]: struct.HashMap.html +/// [`IntoIterator`]: https://doc.rust-lang.org/core/iter/trait.IntoIterator.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut iter = map.into_iter(); +/// let mut vec = vec![iter.next(), iter.next(), iter.next()]; +/// +/// // The `IntoIter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")), Some((2, "b")), Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(iter.next(), None); +/// assert_eq!(iter.next(), None); +/// ``` +pub struct IntoIter { + inner: RawIntoIter<(K, V), A>, +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// An owning iterator over the keys of a `HashMap` in arbitrary order. +/// The iterator element type is `K`. +/// +/// This `struct` is created by the [`into_keys`] method on [`HashMap`]. +/// See its documentation for more. +/// The map cannot be used after calling that method. +/// +/// [`into_keys`]: struct.HashMap.html#method.into_keys +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut keys = map.into_keys(); +/// let mut vec = vec![keys.next(), keys.next(), keys.next()]; +/// +/// // The `IntoKeys` iterator produces keys in arbitrary order, so the +/// // keys must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(1), Some(2), Some(3)]); +/// +/// // It is fused iterator +/// assert_eq!(keys.next(), None); +/// assert_eq!(keys.next(), None); +/// ``` +pub struct IntoKeys { + inner: IntoIter, +} + +impl Iterator for IntoKeys { + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(k, _)| k) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} + +impl ExactSizeIterator for IntoKeys { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoKeys {} + +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(k, _)| k)) + .finish() + } +} + +/// An owning iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `V`. +/// +/// This `struct` is created by the [`into_values`] method on [`HashMap`]. +/// See its documentation for more. The map cannot be used after calling that method. +/// +/// [`into_values`]: struct.HashMap.html#method.into_values +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut values = map.into_values(); +/// let mut vec = vec![values.next(), values.next(), values.next()]; +/// +/// // The `IntoValues` iterator produces values in arbitrary order, so +/// // the values must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some("a"), Some("b"), Some("c")]); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// ``` +pub struct IntoValues { + inner: IntoIter, +} + +impl Iterator for IntoValues { + type Item = V; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[inline] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} + +impl ExactSizeIterator for IntoValues { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoValues {} + +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(_, v)| v)) + .finish() + } +} + +/// An iterator over the keys of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a K`. +/// +/// This `struct` is created by the [`keys`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.HashMap.html#method.keys +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut keys = map.keys(); +/// let mut vec = vec![keys.next(), keys.next(), keys.next()]; +/// +/// // The `Keys` iterator produces keys in arbitrary order, so the +/// // keys must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(&1), Some(&2), Some(&3)]); +/// +/// // It is fused iterator +/// assert_eq!(keys.next(), None); +/// assert_eq!(keys.next(), None); +/// ``` +pub struct Keys<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Keys { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// An iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a V`. +/// +/// This `struct` is created by the [`values`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.HashMap.html#method.values +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut values = map.values(); +/// let mut vec = vec![values.next(), values.next(), values.next()]; +/// +/// // The `Values` iterator produces values in arbitrary order, so the +/// // values must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some(&"a"), Some(&"b"), Some(&"c")]); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// ``` +pub struct Values<'a, K, V> { + inner: Iter<'a, K, V>, +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl Clone for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Values { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +/// A draining iterator over the entries of a `HashMap` in arbitrary +/// order. The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`drain`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.HashMap.html#method.drain +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut drain_iter = map.drain(); +/// let mut vec = vec![drain_iter.next(), drain_iter.next(), drain_iter.next()]; +/// +/// // The `Drain` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")), Some((2, "b")), Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(drain_iter.next(), None); +/// assert_eq!(drain_iter.next(), None); +/// ``` +pub struct Drain<'a, K, V, A: Allocator = Global> { + inner: RawDrain<'a, (K, V), A>, +} + +impl Drain<'_, K, V, A> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +/// A draining iterator over entries of a `HashMap` which don't satisfy the predicate +/// `f(&k, &mut v)` in arbitrary order. The iterator element type is `(K, V)`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`extract_if`]: struct.HashMap.html#method.extract_if +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap = [(1, "a"), (2, "b"), (3, "c")].into(); +/// +/// let mut extract_if = map.extract_if(|k, _v| k % 2 != 0); +/// let mut vec = vec![extract_if.next(), extract_if.next()]; +/// +/// // The `ExtractIf` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [Some((1, "a")),Some((3, "c"))]); +/// +/// // It is fused iterator +/// assert_eq!(extract_if.next(), None); +/// assert_eq!(extract_if.next(), None); +/// drop(extract_if); +/// +/// assert_eq!(map.len(), 1); +/// ``` +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, V, F, A: Allocator = Global> +where + F: FnMut(&K, &mut V) -> bool, +{ + f: F, + inner: RawExtractIf<'a, (K, V), A>, +} + +impl Iterator for ExtractIf<'_, K, V, F, A> +where + F: FnMut(&K, &mut V) -> bool, + A: Allocator, +{ + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + self.inner.next(|&mut (ref k, ref mut v)| (self.f)(k, v)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + +/// A mutable iterator over the values of a `HashMap` in arbitrary order. +/// The iterator element type is `&'a mut V`. +/// +/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.HashMap.html#method.values_mut +/// [`HashMap`]: struct.HashMap.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashMap; +/// +/// let mut map: HashMap<_, _> = [(1, "One".to_owned()), (2, "Two".into())].into(); +/// +/// let mut values = map.values_mut(); +/// values.next().map(|v| v.push_str(" Mississippi")); +/// values.next().map(|v| v.push_str(" Mississippi")); +/// +/// // It is fused iterator +/// assert_eq!(values.next(), None); +/// assert_eq!(values.next(), None); +/// +/// assert_eq!(map.get(&1).unwrap(), &"One Mississippi".to_owned()); +/// assert_eq!(map.get(&2).unwrap(), &"Two Mississippi".to_owned()); +/// ``` +pub struct ValuesMut<'a, K, V> { + inner: IterMut<'a, K, V>, +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry_mut`] docs for usage examples. +/// +/// [`HashMap::raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{RawEntryBuilderMut, RawEntryMut::Vacant, RawEntryMut::Occupied}; +/// use hashbrown::HashMap; +/// use core::hash::{BuildHasher, Hash}; +/// +/// let mut map = HashMap::new(); +/// map.extend([(1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16)]); +/// assert_eq!(map.len(), 6); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let builder: RawEntryBuilderMut<_, _, _> = map.raw_entry_mut(); +/// +/// // Existing key +/// match builder.from_key(&6) { +/// Vacant(_) => unreachable!(), +/// Occupied(view) => assert_eq!(view.get(), &16), +/// } +/// +/// for key in 0..12 { +/// let hash = compute_hash(map.hasher(), &key); +/// let value = map.get(&key).cloned(); +/// let key_value = value.as_ref().map(|v| (&key, v)); +/// +/// println!("Key: {} and value: {:?}", key, value); +/// +/// match map.raw_entry_mut().from_key(&key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// match map.raw_entry_mut().from_hash(hash, |q| *q == key) { +/// Occupied(mut o) => assert_eq!(Some(o.get_key_value()), key_value), +/// Vacant(_) => assert_eq!(value, None), +/// } +/// } +/// +/// assert_eq!(map.len(), 6); +/// ``` +pub struct RawEntryBuilderMut<'a, K, V, S, A: Allocator = Global> { + map: &'a mut HashMap, +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This is a lower-level version of [`Entry`]. +/// +/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], +/// then calling one of the methods of that [`RawEntryBuilderMut`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`Entry`]: enum.Entry.html +/// [`raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawOccupiedEntryMut}; +/// +/// let mut map = HashMap::new(); +/// map.extend([('a', 1), ('b', 2), ('c', 3)]); +/// assert_eq!(map.len(), 3); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// // Existing key (insert) +/// let raw: RawEntryMut<_, _, _> = map.raw_entry_mut().from_key(&'a'); +/// let _raw_o: RawOccupiedEntryMut<_, _, _> = raw.insert('a', 10); +/// assert_eq!(map.len(), 3); +/// +/// // Nonexistent key (insert) +/// map.raw_entry_mut().from_key(&'d').insert('d', 40); +/// assert_eq!(map.len(), 4); +/// +/// // Existing key (or_insert) +/// let hash = compute_hash(map.hasher(), &'b'); +/// let kv = map +/// .raw_entry_mut() +/// .from_key_hashed_nocheck(hash, &'b') +/// .or_insert('b', 20); +/// assert_eq!(kv, (&mut 'b', &mut 2)); +/// *kv.1 = 20; +/// assert_eq!(map.len(), 4); +/// +/// // Nonexistent key (or_insert) +/// let hash = compute_hash(map.hasher(), &'e'); +/// let kv = map +/// .raw_entry_mut() +/// .from_key_hashed_nocheck(hash, &'e') +/// .or_insert('e', 50); +/// assert_eq!(kv, (&mut 'e', &mut 50)); +/// assert_eq!(map.len(), 5); +/// +/// // Existing key (or_insert_with) +/// let hash = compute_hash(map.hasher(), &'c'); +/// let kv = map +/// .raw_entry_mut() +/// .from_hash(hash, |q| q == &'c') +/// .or_insert_with(|| ('c', 30)); +/// assert_eq!(kv, (&mut 'c', &mut 3)); +/// *kv.1 = 30; +/// assert_eq!(map.len(), 5); +/// +/// // Nonexistent key (or_insert_with) +/// let hash = compute_hash(map.hasher(), &'f'); +/// let kv = map +/// .raw_entry_mut() +/// .from_hash(hash, |q| q == &'f') +/// .or_insert_with(|| ('f', 60)); +/// assert_eq!(kv, (&mut 'f', &mut 60)); +/// assert_eq!(map.len(), 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// let mut vec: Vec<_> = map.iter().map(|(&k, &v)| (k, v)).collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [('a', 10), ('b', 20), ('c', 30), ('d', 40), ('e', 50), ('f', 60)]); +/// ``` +pub enum RawEntryMut<'a, K, V, S, A: Allocator = Global> { + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{hash_map::RawEntryMut, HashMap}; + /// let mut map: HashMap<_, _> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => unreachable!(), + /// RawEntryMut::Occupied(_) => { } + /// } + /// ``` + Occupied(RawOccupiedEntryMut<'a, K, V, S, A>), + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::{hash_map::RawEntryMut, HashMap}; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// + /// match map.raw_entry_mut().from_key("a") { + /// RawEntryMut::Occupied(_) => unreachable!(), + /// RawEntryMut::Vacant(_) => { } + /// } + /// ``` + Vacant(RawVacantEntryMut<'a, K, V, S, A>), +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// [`RawEntryMut`]: enum.RawEntryMut.html +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawOccupiedEntryMut}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let _raw_o: RawOccupiedEntryMut<_, _, _> = map.raw_entry_mut().from_key(&"a").insert("a", 100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.raw_entry_mut().from_key(&"a") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// let new_v = (*v) * 10; +/// *v = new_v; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map[&"a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// let hash = compute_hash(map.hasher(), &"c"); +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"c") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c", 30)); +/// } +/// } +/// assert_eq!(map.raw_entry().from_key(&"c"), None); +/// assert_eq!(map.len(), 2); +/// +/// let hash = compute_hash(map.hasher(), &"b"); +/// match map.raw_entry_mut().from_hash(hash, |q| *q == "b") { +/// RawEntryMut::Vacant(_) => unreachable!(), +/// RawEntryMut::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("b", 20)); +/// } +/// } +/// assert_eq!(map.get(&"b"), None); +/// assert_eq!(map.len(), 1); +/// ``` +pub struct RawOccupiedEntryMut<'a, K, V, S, A: Allocator = Global> { + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +unsafe impl Send for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Send, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for RawOccupiedEntryMut<'_, K, V, S, A> +where + K: Sync, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RawEntryMut`] enum. +/// +/// [`RawEntryMut`]: enum.RawEntryMut.html +/// +/// # Examples +/// +/// ``` +/// use core::hash::{BuildHasher, Hash}; +/// use hashbrown::hash_map::{HashMap, RawEntryMut, RawVacantEntryMut}; +/// +/// let mut map = HashMap::<&str, i32>::new(); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// let raw_v: RawVacantEntryMut<_, _, _> = match map.raw_entry_mut().from_key(&"a") { +/// RawEntryMut::Vacant(view) => view, +/// RawEntryMut::Occupied(_) => unreachable!(), +/// }; +/// raw_v.insert("a", 10); +/// assert!(map[&"a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// let hash = compute_hash(map.hasher(), &"b"); +/// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &"b") { +/// RawEntryMut::Occupied(_) => unreachable!(), +/// RawEntryMut::Vacant(view) => { +/// let (k, value) = view.insert("b", 2); +/// assert_eq!((*k, *value), ("b", 2)); +/// *value = 20; +/// } +/// } +/// assert!(map[&"b"] == 20 && map.len() == 2); +/// +/// let hash = compute_hash(map.hasher(), &"c"); +/// match map.raw_entry_mut().from_hash(hash, |q| *q == "c") { +/// RawEntryMut::Occupied(_) => unreachable!(), +/// RawEntryMut::Vacant(view) => { +/// assert_eq!(view.insert("c", 30), (&mut "c", &mut 30)); +/// } +/// } +/// assert!(map[&"c"] == 30 && map.len() == 3); +/// ``` +pub struct RawVacantEntryMut<'a, K, V, S, A: Allocator = Global> { + table: &'a mut RawTable<(K, V), A>, + hash_builder: &'a S, +} + +/// A builder for computing where in a [`HashMap`] a key-value pair would be stored. +/// +/// See the [`HashMap::raw_entry`] docs for usage examples. +/// +/// [`HashMap::raw_entry`]: struct.HashMap.html#method.raw_entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{HashMap, RawEntryBuilder}; +/// use core::hash::{BuildHasher, Hash}; +/// +/// let mut map = HashMap::new(); +/// map.extend([(1, 10), (2, 20), (3, 30)]); +/// +/// fn compute_hash(hash_builder: &S, key: &K) -> u64 { +/// use core::hash::Hasher; +/// let mut state = hash_builder.build_hasher(); +/// key.hash(&mut state); +/// state.finish() +/// } +/// +/// for k in 0..6 { +/// let hash = compute_hash(map.hasher(), &k); +/// let v = map.get(&k).cloned(); +/// let kv = v.as_ref().map(|v| (&k, v)); +/// +/// println!("Key: {} and value: {:?}", k, v); +/// let builder: RawEntryBuilder<_, _, _> = map.raw_entry(); +/// assert_eq!(builder.from_key(&k), kv); +/// assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); +/// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); +/// } +/// ``` +pub struct RawEntryBuilder<'a, K, V, S, A: Allocator = Global> { + map: &'a HashMap, +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_key(&key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + S: BuildHasher, + Q: Hash + Equivalent, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Creates a `RawEntryMut` from the given key and its hash. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_key_hashed_nocheck(hash, &key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[inline] + #[allow(clippy::wrong_self_convention)] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S, A> + where + Q: Equivalent, + { + self.from_hash(hash, equivalent(k)) + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { + /// Creates a `RawEntryMut` from the given hash and matching function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// let entry: RawEntryMut<&str, u32, _> = map.raw_entry_mut().from_hash(hash, |k| k == &key); + /// entry.insert(key, 100); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + self.search(hash, is_match) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> RawEntryMut<'a, K, V, S, A> + where + for<'b> F: FnMut(&'b K) -> bool, + { + match self.map.table.find(hash, |(k, _)| is_match(k)) { + Some(elem) => RawEntryMut::Occupied(RawOccupiedEntryMut { + elem, + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + None => RawEntryMut::Vacant(RawVacantEntryMut { + table: &mut self.map.table, + hash_builder: &self.map.hash_builder, + }), + } + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryBuilder<'a, K, V, S, A> { + /// Access an immutable entry by key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// assert_eq!(map.raw_entry().from_key(&key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key(self, k: &Q) -> Option<(&'a K, &'a V)> + where + S: BuildHasher, + Q: Hash + Equivalent, + { + let hash = make_hash::(&self.map.hash_builder, k); + self.from_key_hashed_nocheck(hash, k) + } + + /// Access an immutable entry by a key and its hash. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)> + where + Q: Equivalent, + { + self.from_hash(hash, equivalent(k)) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn search(self, hash: u64, mut is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + match self.map.table.get(hash, |(k, _)| is_match(k)) { + Some((key, value)) => Some((key, value)), + None => None, + } + } + + /// Access an immutable entry by hash and matching function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::HashMap; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "a"; + /// let hash = compute_hash(map.hasher(), &key); + /// assert_eq!(map.raw_entry().from_hash(hash, |k| k == &key), Some((&"a", &100))); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::wrong_self_convention)] + pub fn from_hash(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> + where + F: FnMut(&K) -> bool, + { + self.search(hash, is_match) + } +} + +impl<'a, K, V, S, A: Allocator> RawEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry, and returns a RawOccupiedEntryMut. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.raw_entry_mut().from_key("horseyland").insert("horseyland", 37); + /// + /// assert_eq!(entry.remove_entry(), ("horseyland", 37)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(mut entry) => { + entry.insert(value); + entry + } + RawEntryMut::Vacant(entry) => entry.insert_entry(key, value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 10).1 *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns mutable references to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// + /// map.raw_entry_mut().from_key("poneyland").or_insert_with(|| { + /// ("poneyland", "hoho".to_string()) + /// }); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with(self, default: F) -> (&'a mut K, &'a mut V) + where + F: FnOnce() -> (K, V), + K: Hash, + S: BuildHasher, + { + match self { + RawEntryMut::Occupied(entry) => entry.into_key_value(), + RawEntryMut::Vacant(entry) => { + let (k, v) = default(); + entry.insert(k, v) + } + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.raw_entry_mut() + /// .from_key("poneyland") + /// .and_modify(|_k, v| { *v += 1 }) + /// .or_insert("poneyland", 0); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut K, &mut V), + { + match self { + RawEntryMut::Occupied(mut entry) => { + { + let (k, v) = entry.get_key_value_mut(); + f(k, v); + } + RawEntryMut::Occupied(entry) + } + RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RawEntryMut; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// RawEntryMut::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// }, + /// RawEntryMut::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + RawEntryMut::Occupied(entry) => entry.replace_entry_with(f), + RawEntryMut::Vacant(_) => self, + } + } +} + +impl<'a, K, V, S, A: Allocator> RawOccupiedEntryMut<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.key(), &"a") + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Gets a mutable reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// *o.key_mut() = key_two.clone(); + /// } + /// } + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key_mut(&mut self) -> &mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Converts the entry into a mutable reference to the key in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// let inside_key: &mut Rc<&str>; + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => inside_key = o.into_key(), + /// } + /// *inside_key = key_two.clone(); + /// + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> &'a mut K { + unsafe { &mut self.elem.as_mut().0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.get(), &100), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// let value: &mut u32; + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => value = o.into_mut(), + /// } + /// *value += 900; + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => *o.get_mut() += 900, + /// } + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Gets a reference to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.get_key_value(), (&"a", &100)), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value(&self) -> (&K, &V) { + unsafe { + let (key, value) = self.elem.as_ref(); + (key, value) + } + } + + /// Gets a mutable reference to the key and value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// let (inside_key, inside_value) = o.get_key_value_mut(); + /// *inside_key = key_two.clone(); + /// *inside_value = 100; + /// } + /// } + /// assert_eq!(map[&key_two], 100); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Converts the OccupiedEntry into a mutable reference to the key and value in the entry + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// let inside_key: &mut Rc<&str>; + /// let inside_value: &mut u32; + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => { + /// let tuple = o.into_key_value(); + /// inside_key = tuple.0; + /// inside_value = tuple.1; + /// } + /// } + /// *inside_key = key_two.clone(); + /// *inside_value = 100; + /// assert_eq!(map[&key_two], 100); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key_value(self) -> (&'a mut K, &'a mut V) { + unsafe { + let &mut (ref mut key, ref mut value) = self.elem.as_mut(); + (key, value) + } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => assert_eq!(o.insert(1000), 100), + /// } + /// + /// assert_eq!(map[&"a"], 1000); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// use std::rc::Rc; + /// + /// let key_one = Rc::new("a"); + /// let key_two = Rc::new("a"); + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(key_one.clone(), 10); + /// + /// assert_eq!(map[&key_one], 10); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.raw_entry_mut().from_key(&key_one) { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(mut o) => { + /// let old_key = o.insert_key(key_two.clone()); + /// assert!(Rc::ptr_eq(&old_key, &key_one)); + /// } + /// } + /// assert_eq!(map[&key_two], 10); + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_key(&mut self, key: K) -> K { + mem::replace(self.key_mut(), key) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.remove(), 100), + /// } + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => assert_eq!(o.remove_entry(), ("a", 100)), + /// } + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem).0 } + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// let raw_entry = match map.raw_entry_mut().from_key(&"a") { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => o.replace_entry_with(|k, v| { + /// assert_eq!(k, &"a"); + /// assert_eq!(v, 100); + /// Some(v + 900) + /// }), + /// }; + /// let raw_entry = match raw_entry { + /// RawEntryMut::Vacant(_) => panic!(), + /// RawEntryMut::Occupied(o) => o.replace_entry_with(|k, v| { + /// assert_eq!(k, &"a"); + /// assert_eq!(v, 1000); + /// None + /// }), + /// }; + /// match raw_entry { + /// RawEntryMut::Vacant(_) => { }, + /// RawEntryMut::Occupied(_) => panic!(), + /// }; + /// assert_eq!(map.get(&"a"), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> RawEntryMut<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let still_occupied = self + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + f(&key, value).map(|new_value| (key, new_value)) + }); + + if still_occupied { + RawEntryMut::Occupied(self) + } else { + RawEntryMut::Vacant(RawVacantEntryMut { + table: self.table, + hash_builder: self.hash_builder, + }) + } + } + } +} + +impl<'a, K, V, S, A: Allocator> RawVacantEntryMut<'a, K, V, S, A> { + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// + /// match map.raw_entry_mut().from_key(&"c") { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!(v.insert("c", 300), (&mut "c", &mut 300)), + /// } + /// + /// assert_eq!(map[&"c"], 300); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let hash = make_hash::(self.hash_builder, &key); + self.insert_hashed_nocheck(hash, key, value) + } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn compute_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let mut map: HashMap<&str, u32> = [("a", 100), ("b", 200)].into(); + /// let key = "c"; + /// let hash = compute_hash(map.hasher(), &key); + /// + /// match map.raw_entry_mut().from_key_hashed_nocheck(hash, &key) { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!( + /// v.insert_hashed_nocheck(hash, key, 300), + /// (&mut "c", &mut 300) + /// ), + /// } + /// + /// assert_eq!(map[&"c"], 300); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::shadow_unrelated)] + pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) + where + K: Hash, + S: BuildHasher, + { + let &mut (ref mut k, ref mut v) = self.table.insert_entry( + hash, + (key, value), + make_hasher::<_, V, S>(self.hash_builder), + ); + (k, v) + } + + /// Set the value of an entry with a custom hasher function. + /// + /// # Examples + /// + /// ``` + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::hash_map::{HashMap, RawEntryMut}; + /// + /// fn make_hasher(hash_builder: &S) -> impl Fn(&K) -> u64 + '_ + /// where + /// K: Hash + ?Sized, + /// S: BuildHasher, + /// { + /// move |key: &K| { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// } + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let key = "a"; + /// let hash_builder = map.hasher().clone(); + /// let hash = make_hasher(&hash_builder)(&key); + /// + /// match map.raw_entry_mut().from_hash(hash, |q| q == &key) { + /// RawEntryMut::Occupied(_) => panic!(), + /// RawEntryMut::Vacant(v) => assert_eq!( + /// v.insert_with_hasher(hash, key, 100, make_hasher(&hash_builder)), + /// (&mut "a", &mut 100) + /// ), + /// } + /// map.extend([("b", 200), ("c", 300), ("d", 400), ("e", 500), ("f", 600)]); + /// assert_eq!(map[&"a"], 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_with_hasher( + self, + hash: u64, + key: K, + value: V, + hasher: H, + ) -> (&'a mut K, &'a mut V) + where + H: Fn(&K) -> u64, + { + let &mut (ref mut k, ref mut v) = self + .table + .insert_entry(hash, (key, value), |x| hasher(&x.0)); + (k, v) + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let hash = make_hash::(self.hash_builder, &key); + let elem = self.table.insert( + hash, + (key, value), + make_hasher::<_, V, S>(self.hash_builder), + ); + RawOccupiedEntryMut { + elem, + table: self.table, + hash_builder: self.hash_builder, + } + } +} + +impl Debug for RawEntryBuilderMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +impl Debug for RawEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), + RawEntryMut::Occupied(ref o) => f.debug_tuple("RawEntry").field(o).finish(), + } + } +} + +impl Debug for RawOccupiedEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawOccupiedEntryMut") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +impl Debug for RawVacantEntryMut<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawVacantEntryMut").finish() + } +} + +impl Debug for RawEntryBuilder<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RawEntryBuilder").finish() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry`]: struct.HashMap.html#method.entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert) +/// let entry: Entry<_, _, _> = map.entry("a"); +/// let _raw_o: OccupiedEntry<_, _, _> = entry.insert(1); +/// assert_eq!(map.len(), 3); +/// // Nonexistent key (insert) +/// map.entry("d").insert(4); +/// +/// // Existing key (or_insert) +/// let v = map.entry("b").or_insert(2); +/// assert_eq!(std::mem::replace(v, 2), 20); +/// // Nonexistent key (or_insert) +/// map.entry("e").or_insert(5); +/// +/// // Existing key (or_insert_with) +/// let v = map.entry("c").or_insert_with(|| 3); +/// assert_eq!(std::mem::replace(v, 3), 30); +/// // Nonexistent key (or_insert_with) +/// map.entry("f").or_insert_with(|| 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// let mut vec: Vec<_> = map.iter().map(|(&k, &v)| (k, v)).collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3), ("d", 4), ("e", 5), ("f", 6)]); +/// ``` +pub enum Entry<'a, K, V, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// let mut map: HashMap<_, _> = [("a", 100), ("b", 200)].into(); + /// + /// match map.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, K, V, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// + /// match map.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, K, V, S, A>), +} + +impl Debug for Entry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, OccupiedEntry}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a", 10), ("b", 20), ("c", 30)]); +/// +/// let _entry_o: OccupiedEntry<_, _, _> = map.entry("a").insert(100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// *v *= 10; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map[&"a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// match map.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c", 30)); +/// } +/// } +/// assert_eq!(map.get(&"c"), None); +/// assert_eq!(map.len(), 2); +/// ``` +pub struct OccupiedEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { + hash: u64, + key: Option, + elem: Bucket<(K, V)>, + table: &'a mut HashMap, +} + +unsafe impl Send for OccupiedEntry<'_, K, V, S, A> +where + K: Send, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for OccupiedEntry<'_, K, V, S, A> +where + K: Sync, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +impl Debug for OccupiedEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{Entry, HashMap, VacantEntry}; +/// +/// let mut map = HashMap::<&str, i32>::new(); +/// +/// let entry_v: VacantEntry<_, _, _> = match map.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(10); +/// assert!(map[&"a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// match map.entry("b") { +/// Entry::Occupied(_) => unreachable!(), +/// Entry::Vacant(view) => { +/// let value = view.insert(2); +/// assert_eq!(*value, 2); +/// *value = 20; +/// } +/// } +/// assert!(map[&"b"] == 20 && map.len() == 2); +/// ``` +pub struct VacantEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { + hash: u64, + key: K, + table: &'a mut HashMap, +} + +impl Debug for VacantEntry<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied, +/// with any borrowed form of the map's key type. +/// +/// +/// This `enum` is constructed from the [`entry_ref`] method on [`HashMap`]. +/// +/// [`Hash`] and [`Eq`] on the borrowed form of the map's key type *must* match those +/// for the key type. It also require that key may be constructed from the borrowed +/// form through the [`From`] trait. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry_ref`]: struct.HashMap.html#method.entry_ref +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, OccupiedEntryRef}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a".to_owned(), 10), ("b".into(), 20), ("c".into(), 30)]); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert) +/// let key = String::from("a"); +/// let entry: EntryRef<_, _, _, _> = map.entry_ref(&key); +/// let _raw_o: OccupiedEntryRef<_, _, _, _> = entry.insert(1); +/// assert_eq!(map.len(), 3); +/// // Nonexistent key (insert) +/// map.entry_ref("d").insert(4); +/// +/// // Existing key (or_insert) +/// let v = map.entry_ref("b").or_insert(2); +/// assert_eq!(std::mem::replace(v, 2), 20); +/// // Nonexistent key (or_insert) +/// map.entry_ref("e").or_insert(5); +/// +/// // Existing key (or_insert_with) +/// let v = map.entry_ref("c").or_insert_with(|| 3); +/// assert_eq!(std::mem::replace(v, 3), 30); +/// // Nonexistent key (or_insert_with) +/// map.entry_ref("f").or_insert_with(|| 6); +/// +/// println!("Our HashMap: {:?}", map); +/// +/// for (key, value) in ["a", "b", "c", "d", "e", "f"].into_iter().zip(1..=6) { +/// assert_eq!(map[key], value) +/// } +/// assert_eq!(map.len(), 6); +/// ``` +pub enum EntryRef<'a, 'b, K, Q: ?Sized, V, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// let mut map: HashMap<_, _> = [("a".to_owned(), 100), ("b".into(), 200)].into(); + /// + /// match map.entry_ref("a") { + /// EntryRef::Vacant(_) => unreachable!(), + /// EntryRef::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntryRef<'a, 'b, K, Q, V, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// let mut map: HashMap = HashMap::new(); + /// + /// match map.entry_ref("a") { + /// EntryRef::Occupied(_) => unreachable!(), + /// EntryRef::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntryRef<'a, 'b, K, Q, V, S, A>), +} + +impl, Q: ?Sized + Debug, V: Debug, S, A: Allocator> Debug + for EntryRef<'_, '_, K, Q, V, S, A> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + EntryRef::Vacant(ref v) => f.debug_tuple("EntryRef").field(v).finish(), + EntryRef::Occupied(ref o) => f.debug_tuple("EntryRef").field(o).finish(), + } + } +} + +enum KeyOrRef<'a, K, Q: ?Sized> { + Borrowed(&'a Q), + Owned(K), +} + +impl<'a, K, Q: ?Sized> KeyOrRef<'a, K, Q> { + fn into_owned(self) -> K + where + K: From<&'a Q>, + { + match self { + Self::Borrowed(borrowed) => borrowed.into(), + Self::Owned(owned) => owned, + } + } +} + +impl<'a, K: Borrow, Q: ?Sized> AsRef for KeyOrRef<'a, K, Q> { + fn as_ref(&self) -> &Q { + match self { + Self::Borrowed(borrowed) => borrowed, + Self::Owned(owned) => owned.borrow(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`EntryRef`] enum. +/// +/// [`EntryRef`]: enum.EntryRef.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, OccupiedEntryRef}; +/// +/// let mut map = HashMap::new(); +/// map.extend([("a".to_owned(), 10), ("b".into(), 20), ("c".into(), 30)]); +/// +/// let key = String::from("a"); +/// let _entry_o: OccupiedEntryRef<_, _, _, _> = map.entry_ref(&key).insert(100); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (insert and update) +/// match map.entry_ref("a") { +/// EntryRef::Vacant(_) => unreachable!(), +/// EntryRef::Occupied(mut view) => { +/// assert_eq!(view.get(), &100); +/// let v = view.get_mut(); +/// *v *= 10; +/// assert_eq!(view.insert(1111), 1000); +/// } +/// } +/// +/// assert_eq!(map["a"], 1111); +/// assert_eq!(map.len(), 3); +/// +/// // Existing key (take) +/// match map.entry_ref("c") { +/// EntryRef::Vacant(_) => unreachable!(), +/// EntryRef::Occupied(view) => { +/// assert_eq!(view.remove_entry(), ("c".to_owned(), 30)); +/// } +/// } +/// assert_eq!(map.get("c"), None); +/// assert_eq!(map.len(), 2); +/// ``` +pub struct OccupiedEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator = Global> { + hash: u64, + key: Option>, + elem: Bucket<(K, V)>, + table: &'a mut HashMap, +} + +unsafe impl<'a, 'b, K, Q, V, S, A> Send for OccupiedEntryRef<'a, 'b, K, Q, V, S, A> +where + K: Send, + Q: Sync + ?Sized, + V: Send, + S: Send, + A: Send + Allocator, +{ +} +unsafe impl<'a, 'b, K, Q, V, S, A> Sync for OccupiedEntryRef<'a, 'b, K, Q, V, S, A> +where + K: Sync, + Q: Sync + ?Sized, + V: Sync, + S: Sync, + A: Sync + Allocator, +{ +} + +impl, Q: ?Sized + Debug, V: Debug, S, A: Allocator> Debug + for OccupiedEntryRef<'_, '_, K, Q, V, S, A> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntryRef") + .field("key", &self.key().borrow()) + .field("value", &self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`EntryRef`] enum. +/// +/// [`EntryRef`]: enum.EntryRef.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{EntryRef, HashMap, VacantEntryRef}; +/// +/// let mut map = HashMap::::new(); +/// +/// let entry_v: VacantEntryRef<_, _, _, _> = match map.entry_ref("a") { +/// EntryRef::Vacant(view) => view, +/// EntryRef::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(10); +/// assert!(map["a"] == 10 && map.len() == 1); +/// +/// // Nonexistent key (insert and update) +/// match map.entry_ref("b") { +/// EntryRef::Occupied(_) => unreachable!(), +/// EntryRef::Vacant(view) => { +/// let value = view.insert(2); +/// assert_eq!(*value, 2); +/// *value = 20; +/// } +/// } +/// assert!(map["b"] == 20 && map.len() == 2); +/// ``` +pub struct VacantEntryRef<'a, 'b, K, Q: ?Sized, V, S, A: Allocator = Global> { + hash: u64, + key: KeyOrRef<'b, K, Q>, + table: &'a mut HashMap, +} + +impl, Q: ?Sized + Debug, V, S, A: Allocator> Debug + for VacantEntryRef<'_, '_, K, Q, V, S, A> +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntryRef").field(&self.key()).finish() + } +} + +/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists. +/// +/// Contains the occupied entry, and the value that was not inserted. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_map::{HashMap, OccupiedError}; +/// +/// let mut map: HashMap<_, _> = [("a", 10), ("b", 20)].into(); +/// +/// // try_insert method returns mutable reference to the value if keys are vacant, +/// // but if the map did have key present, nothing is updated, and the provided +/// // value is returned inside `Err(_)` variant +/// match map.try_insert("a", 100) { +/// Err(OccupiedError { mut entry, value }) => { +/// assert_eq!(entry.key(), &"a"); +/// assert_eq!(value, 100); +/// assert_eq!(entry.insert(100), 10) +/// } +/// _ => unreachable!(), +/// } +/// assert_eq!(map[&"a"], 100); +/// ``` +pub struct OccupiedError<'a, K, V, S, A: Allocator = Global> { + /// The entry in the map that was already occupied. + pub entry: OccupiedEntry<'a, K, V, S, A>, + /// The value which was not inserted, because the entry was already occupied. + pub value: V, +} + +impl Debug for OccupiedError<'_, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedError") + .field("key", self.entry.key()) + .field("old_value", self.entry.get()) + .field("new_value", &self.value) + .finish() + } +} + +impl<'a, K: Debug, V: Debug, S, A: Allocator> fmt::Display for OccupiedError<'a, K, V, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "failed to insert {:?}, key {:?} already exists with value {:?}", + self.value, + self.entry.key(), + self.entry.get(), + ) + } +} + +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + /// Creates an iterator over the entries of a `HashMap` in arbitrary order. + /// The iterator element type is `(&'a K, &'a V)`. + /// + /// Return the same `Iter` struct as by the [`iter`] method on [`HashMap`]. + /// + /// [`iter`]: struct.HashMap.html#method.iter + /// [`HashMap`]: struct.HashMap.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let map_one: HashMap<_, _> = [(1, "a"), (2, "b"), (3, "c")].into(); + /// let mut map_two = HashMap::new(); + /// + /// for (key, value) in &map_one { + /// println!("Key: {}, Value: {}", key, value); + /// map_two.insert_unique_unchecked(*key, *value); + /// } + /// + /// assert_eq!(map_one, map_two); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +impl<'a, K, V, S, A: Allocator> IntoIterator for &'a mut HashMap { + type Item = (&'a K, &'a mut V); + type IntoIter = IterMut<'a, K, V>; + + /// Creates an iterator over the entries of a `HashMap` in arbitrary order + /// with mutable references to the values. The iterator element type is + /// `(&'a K, &'a mut V)`. + /// + /// Return the same `IterMut` struct as by the [`iter_mut`] method on + /// [`HashMap`]. + /// + /// [`iter_mut`]: struct.HashMap.html#method.iter_mut + /// [`HashMap`]: struct.HashMap.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<_, _> = [("a", 1), ("b", 2), ("c", 3)].into(); + /// + /// for (key, value) in &mut map { + /// println!("Key: {}, Value: {}", key, value); + /// *value *= 2; + /// } + /// + /// let mut vec = map.iter().collect::>(); + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(&"a", &2), (&"b", &4), (&"c", &6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IterMut<'a, K, V> { + self.iter_mut() + } +} + +impl IntoIterator for HashMap { + type Item = (K, V); + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let map: HashMap<_, _> = [("a", 1), ("b", 2), ("c", 3)].into(); + /// + /// // Not possible with .iter() + /// let mut vec: Vec<(&str, i32)> = map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so + /// // the items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [("a", 1), ("b", 2), ("c", 3)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.table.into_iter(), + } + } +} + +impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_ref(); + Some((&r.0, &r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_ref(); + f(acc, (k, v)) + }) + } +} +impl ExactSizeIterator for Iter<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, K, V> {} + +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a K, &'a mut V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(x) => unsafe { + let r = x.as_mut(); + Some((&r.0, &mut r.1)) + }, + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, x| unsafe { + let (k, v) = x.as_mut(); + f(acc, (k, v)) + }) + } +} +impl ExactSizeIterator for IterMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IterMut<'_, K, V> {} + +impl fmt::Debug for IterMut<'_, K, V> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (k, _)| f(acc, k)) + } +} +impl ExactSizeIterator for Keys<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Keys<'_, K, V> {} + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +impl ExactSizeIterator for Values<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Values<'_, K, V> {} + +impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { + type Item = &'a mut V; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a mut V> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some((_, v)) => Some(v), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, |acc, (_, v)| f(acc, v)) + } +} +impl ExactSizeIterator for ValuesMut<'_, K, V> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for ValuesMut<'_, K, V> {} + +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.inner.iter().map(|(_, val)| val)) + .finish() + } +} + +impl<'a, K, V, A: Allocator> Iterator for Drain<'a, K, V, A> { + type Item = (K, V); + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<(K, V)> { + self.inner.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} +impl ExactSizeIterator for Drain<'_, K, V, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Drain<'_, K, V, A> {} + +impl fmt::Debug for Drain<'_, K, V, A> +where + K: fmt::Debug, + V: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl<'a, K, V, S, A: Allocator> Entry<'a, K, V, S, A> { + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(mut entry) => { + entry.insert(value); + entry + } + Entry::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert_with(|| 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry("poneyland").or_insert_with(|| 10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function a reference to the key that was moved during the `.entry(key)` method call. + /// + /// The reference to the moved key is provided so that cloning or copying the key is + /// unnecessary, unlike with `.or_insert_with(|| ... )`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, usize> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// assert_eq!(map["poneyland"], 9); + /// + /// // existing key + /// *map.entry("poneyland").or_insert_with_key(|key| key.chars().count() * 10) *= 2; + /// assert_eq!(map["poneyland"], 18); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(3); + /// // existing key + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(map.entry("horseland").key(), &"horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Entry::Occupied(ref entry) => entry.key(), + Entry::Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// Entry::Vacant(e) => assert_eq!(e.key(), &"poneyland"), + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + Entry::Occupied(entry) => entry.replace_entry_with(f), + Entry::Vacant(_) => self, + } + } +} + +impl<'a, K, V: Default, S, A: Allocator> Entry<'a, K, V, S, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry("poneyland").or_default(); + /// assert_eq!(map["poneyland"], None); + /// + /// map.insert("horseland", Some(3)); + /// + /// // existing key + /// assert_eq!(map.entry("horseland").or_default(), &mut Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.key(), &"poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// assert_eq!(o.remove_entry(), ("poneyland", 12)); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// match map.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &12), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// + /// let value: &mut u32; + /// match map.entry("poneyland") { + /// Entry::Occupied(entry) => value = entry.into_mut(), + /// Entry::Vacant(_) => panic!(), + /// } + /// *value += 10; + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntry was created through [`Entry::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let key_one = Rc::new("Stringthing".to_string()); + /// let key_two = Rc::new("Stringthing".to_string()); + /// + /// map.insert(key_one.clone(), 15); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match map.entry(key_two.clone()) { + /// Entry::Occupied(entry) => { + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// assert!(Rc::ptr_eq(&key_one, &old_key) && old_value == 15); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// assert_eq!(map[&"Stringthing".to_owned()], 16); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry(self, value: V) -> (K, V) { + let entry = unsafe { self.elem.as_mut() }; + + let old_key = mem::replace(&mut entry.0, self.key.unwrap()); + let old_value = mem::replace(&mut entry.1, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntry was created through [`Entry::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, usize> = HashMap::with_capacity(6); + /// let mut keys_one: Vec> = Vec::with_capacity(6); + /// let mut keys_two: Vec> = Vec::with_capacity(6); + /// + /// for (value, key) in ["a", "b", "c", "d", "e", "f"].into_iter().enumerate() { + /// let rc_key = Rc::new(key.to_owned()); + /// keys_one.push(rc_key.clone()); + /// map.insert(rc_key.clone(), value); + /// keys_two.push(Rc::new(key.to_owned())); + /// } + /// + /// assert!( + /// keys_one.iter().all(|key| Rc::strong_count(key) == 2) + /// && keys_two.iter().all(|key| Rc::strong_count(key) == 1) + /// ); + /// + /// reclaim_memory(&mut map, &keys_two); + /// + /// assert!( + /// keys_one.iter().all(|key| Rc::strong_count(key) == 1) + /// && keys_two.iter().all(|key| Rc::strong_count(key) == 2) + /// ); + /// + /// fn reclaim_memory(map: &mut HashMap, usize>, keys: &[Rc]) { + /// for key in keys { + /// if let Entry::Occupied(entry) = map.entry(key.clone()) { + /// // Replaces the entry's key with our version of it in `keys`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_key(self) -> K { + let entry = unsafe { self.elem.as_mut() }; + mem::replace(&mut entry.0, self.key.unwrap()) + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.insert("poneyland", 42); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => { + /// e.replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }) + /// } + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => e.replace_entry_with(|_k, _v| None), + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> Entry<'a, K, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let mut spare_key = None; + + self.table + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) + } else { + spare_key = Some(key); + None + } + }); + + if let Some(key) = spare_key { + Entry::Vacant(VacantEntry { + hash: self.hash, + key, + table: self.table, + }) + } else { + Entry::Occupied(self) + } + } + } +} + +impl<'a, K, V, S, A: Allocator> VacantEntry<'a, K, V, S, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{Entry, HashMap}; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// match map.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_key(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V + where + K: Hash, + S: BuildHasher, + { + let table = &mut self.table.table; + let entry = table.insert_entry( + self.hash, + (self.key, value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + &mut entry.1 + } + + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, S, A> + where + K: Hash, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (self.key, value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + OccupiedEntry { + hash: self.hash, + key: None, + elem, + table: self.table, + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { + /// Sets the value of the entry, and returns an OccupiedEntryRef. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// let entry = map.entry_ref("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), "horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> OccupiedEntryRef<'a, 'b, K, Q, V, S, A> + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(mut entry) => { + entry.insert(value); + entry + } + EntryRef::Vacant(entry) => entry.insert_entry(value), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert_with(|| 3); + /// assert_eq!(map["poneyland"], 3); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert_with(|| 10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(default()), + } + } + + /// Ensures a value is in the entry by inserting, if empty, the result of the default function. + /// This method allows for generating key-derived values for insertion by providing the default + /// function an access to the borrower form of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_insert_with_key(|key| key.chars().count()); + /// assert_eq!(map["poneyland"], 9); + /// + /// // existing key + /// *map.entry_ref("poneyland").or_insert_with_key(|key| key.chars().count() * 10) *= 2; + /// assert_eq!(map["poneyland"], 18); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with_key V>(self, default: F) -> &'a mut V + where + K: Hash + Borrow + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => { + let value = default(entry.key.as_ref()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(3); + /// // existing key + /// assert_eq!(map.entry_ref("poneyland").key(), "poneyland"); + /// // nonexistent key + /// assert_eq!(map.entry_ref("horseland").key(), "horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &Q + where + K: Borrow, + { + match *self { + EntryRef::Occupied(ref entry) => entry.key().borrow(), + EntryRef::Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// map.entry_ref("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry_ref("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + EntryRef::Occupied(mut entry) => { + f(entry.get_mut()); + EntryRef::Occupied(entry) + } + EntryRef::Vacant(entry) => EntryRef::Vacant(entry), + } + } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// + /// let entry = map + /// .entry_ref("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// EntryRef::Vacant(e) => { + /// assert_eq!(e.key(), "poneyland"); + /// } + /// EntryRef::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland".to_string(), 42); + /// + /// let entry = map + /// .entry_ref("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, "poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// EntryRef::Occupied(e) => { + /// assert_eq!(e.key(), "poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// EntryRef::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .entry_ref("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// EntryRef::Vacant(e) => assert_eq!(e.key(), "poneyland"), + /// EntryRef::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + EntryRef::Occupied(entry) => entry.replace_entry_with(f), + EntryRef::Vacant(_) => self, + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V: Default, S, A: Allocator> EntryRef<'a, 'b, K, Q, V, S, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap> = HashMap::new(); + /// + /// // nonexistent key + /// map.entry_ref("poneyland").or_default(); + /// assert_eq!(map["poneyland"], None); + /// + /// map.insert("horseland".to_string(), Some(3)); + /// + /// // existing key + /// assert_eq!(map.entry_ref("horseland").or_default(), &mut Some(3)); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + match self { + EntryRef::Occupied(entry) => entry.into_mut(), + EntryRef::Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> OccupiedEntryRef<'a, 'b, K, Q, V, S, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// match map.entry_ref("poneyland") { + /// EntryRef::Vacant(_) => panic!(), + /// EntryRef::Occupied(entry) => assert_eq!(entry.key(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry_ref("poneyland").or_insert(12); + /// + /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") { + /// // We delete the entry from the map. + /// assert_eq!(o.remove_entry(), ("poneyland".to_owned(), 12)); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements but capacity is equal to the old one + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// match map.entry_ref("poneyland") { + /// EntryRef::Vacant(_) => panic!(), + /// EntryRef::Occupied(entry) => assert_eq!(entry.get(), &12), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntryRef` which may outlive the + /// destruction of the `EntryRef` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let EntryRef::Occupied(mut o) = map.entry_ref("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the OccupiedEntryRef into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `OccupiedEntryRef`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// let value: &mut u32; + /// match map.entry_ref("poneyland") { + /// EntryRef::Occupied(entry) => value = entry.into_mut(), + /// EntryRef::Vacant(_) => panic!(), + /// } + /// *value += 10; + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.entry_ref("poneyland").or_insert(12); + /// + /// if let EntryRef::Occupied(mut o) = map.entry_ref("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// // The map is empty + /// assert!(map.is_empty() && map.capacity() == 0); + /// + /// map.entry_ref("poneyland").or_insert(12); + /// + /// if let EntryRef::Occupied(o) = map.entry_ref("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// // Now map hold none elements but capacity is equal to the old one + /// assert!(map.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntryRef was created through [`EntryRef::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let key: Rc = Rc::from("Stringthing"); + /// + /// map.insert(key.clone(), 15); + /// assert_eq!(Rc::strong_count(&key), 2); + /// + /// match map.entry_ref("Stringthing") { + /// EntryRef::Occupied(entry) => { + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// assert!(Rc::ptr_eq(&key, &old_key) && old_value == 15); + /// } + /// EntryRef::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(Rc::strong_count(&key), 1); + /// assert_eq!(map["Stringthing"], 16); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry(self, value: V) -> (K, V) + where + K: From<&'b Q>, + { + let entry = unsafe { self.elem.as_mut() }; + + let old_key = mem::replace(&mut entry.0, self.key.unwrap().into_owned()); + let old_value = mem::replace(&mut entry.1, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntryRef was created through [`EntryRef::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, usize> = HashMap::with_capacity(6); + /// let mut keys: Vec> = Vec::with_capacity(6); + /// + /// for (value, key) in ["a", "b", "c", "d", "e", "f"].into_iter().enumerate() { + /// let rc_key: Rc = Rc::from(key); + /// keys.push(rc_key.clone()); + /// map.insert(rc_key.clone(), value); + /// } + /// + /// assert!(keys.iter().all(|key| Rc::strong_count(key) == 2)); + /// + /// // It doesn't matter that we kind of use a vector with the same keys, + /// // because all keys will be newly created from the references + /// reclaim_memory(&mut map, &keys); + /// + /// assert!(keys.iter().all(|key| Rc::strong_count(key) == 1)); + /// + /// fn reclaim_memory(map: &mut HashMap, usize>, keys: &[Rc]) { + /// for key in keys { + /// if let EntryRef::Occupied(entry) = map.entry_ref(key.as_ref()) { + /// // Replaces the entry's key with our version of it in `keys`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_key(self) -> K + where + K: From<&'b Q>, + { + let entry = unsafe { self.elem.as_mut() }; + mem::replace(&mut entry.0, self.key.unwrap().into_owned()) + } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// map.insert("poneyland".to_string(), 42); + /// + /// let entry = match map.entry_ref("poneyland") { + /// EntryRef::Occupied(e) => { + /// e.replace_entry_with(|k, v| { + /// assert_eq!(k, "poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }) + /// } + /// EntryRef::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// EntryRef::Occupied(e) => { + /// assert_eq!(e.key(), "poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// EntryRef::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = match map.entry_ref("poneyland") { + /// EntryRef::Occupied(e) => e.replace_entry_with(|_k, _v| None), + /// EntryRef::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// EntryRef::Vacant(e) => { + /// assert_eq!(e.key(), "poneyland"); + /// } + /// EntryRef::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> EntryRef<'a, 'b, K, Q, V, S, A> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let mut spare_key = None; + + self.table + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) + } else { + spare_key = Some(KeyOrRef::Owned(key)); + None + } + }); + + if let Some(key) = spare_key { + EntryRef::Vacant(VacantEntryRef { + hash: self.hash, + key, + table: self.table, + }) + } else { + EntryRef::Occupied(self) + } + } + } +} + +impl<'a, 'b, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'a, 'b, K, Q, V, S, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `VacantEntryRef`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// assert_eq!(map.entry_ref(key).key(), "poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &Q + where + K: Borrow, + { + self.key.as_ref() + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{EntryRef, HashMap}; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// + /// match map.entry_ref(key) { + /// EntryRef::Occupied(_) => panic!(), + /// EntryRef::Vacant(v) => assert_eq!(v.into_key(), "poneyland".to_owned()), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K + where + K: From<&'b Q>, + { + self.key.into_owned() + } + + /// Sets the value of the entry with the VacantEntryRef's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::EntryRef; + /// + /// let mut map: HashMap = HashMap::new(); + /// let key: &str = "poneyland"; + /// + /// if let EntryRef::Vacant(o) = map.entry_ref(key) { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + let table = &mut self.table.table; + let entry = table.insert_entry( + self.hash, + (self.key.into_owned(), value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + &mut entry.1 + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self, value: V) -> OccupiedEntryRef<'a, 'b, K, Q, V, S, A> + where + K: Hash + From<&'b Q>, + S: BuildHasher, + { + let elem = self.table.table.insert( + self.hash, + (self.key.into_owned(), value), + make_hasher::<_, V, S>(&self.table.hash_builder), + ); + OccupiedEntryRef { + hash: self.hash, + key: None, + elem, + table: self.table, + } + } +} + +impl FromIterator<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: T) -> Self { + let iter = iter.into_iter(); + let mut map = + Self::with_capacity_and_hasher_in(iter.size_hint().0, S::default(), A::default()); + iter.for_each(|(k, v)| { + map.insert(k, v); + }); + map + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl Extend<(K, V)> for HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let some_iter = [(1, 1), (2, 2)].into_iter(); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(some_vec); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(some_arr); + /// let old_map_len = map.len(); + /// + /// // You can also extend from another HashMap + /// let mut new_map = HashMap::new(); + /// new_map.extend(map); + /// assert_eq!(new_map.len(), old_map_len); + /// + /// let mut vec: Vec<_> = new_map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let iter = iter.into_iter(); + let reserve = if self.is_empty() { + iter.size_hint().0 + } else { + (iter.size_hint().0 + 1) / 2 + }; + self.reserve(reserve); + iter.for_each(move |(k, v)| { + self.insert(k, v); + }); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (K, V)) { + self.insert(k, v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + // Keys may be already present or show multiple times in the iterator. + // Reserve the entire hint lower bound if the map is empty. + // Otherwise reserve half the hint (rounded up), so the map + // will only resize twice in the worst case. + let reserve = if self.is_empty() { + additional + } else { + (additional + 1) / 2 + }; + self.reserve(reserve); + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl<'a, K, V, S, A> Extend<(&'a K, &'a V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// The keys and values must implement [`Copy`] trait. + /// + /// [`Copy`]: https://doc.rust-lang.org/core/marker/trait.Copy.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let arr = [(1, 1), (2, 2)]; + /// let some_iter = arr.iter().map(|(k, v)| (k, v)); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(some_vec.iter().map(|(k, v)| (k, v))); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(some_arr.iter().map(|(k, v)| (k, v))); + /// + /// // You can also extend from another HashMap + /// let mut new_map = HashMap::new(); + /// new_map.extend(&map); + /// assert_eq!(new_map, map); + /// + /// let mut vec: Vec<_> = new_map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, (k, v): (&'a K, &'a V)) { + self.insert(*k, *v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional); + } +} + +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. +impl<'a, K, V, S, A> Extend<&'a (K, V)> for HashMap +where + K: Eq + Hash + Copy, + V: Copy, + S: BuildHasher, + A: Allocator, +{ + /// Inserts all new key-values from the iterator to existing `HashMap`. + /// Replace values with existing keys with new values returned from the iterator. + /// The keys and values must implement [`Copy`] trait. + /// + /// [`Copy`]: https://doc.rust-lang.org/core/marker/trait.Copy.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1, 100); + /// + /// let arr = [(1, 1), (2, 2)]; + /// let some_iter = arr.iter(); + /// map.extend(some_iter); + /// // Replace values with existing keys with new values returned from the iterator. + /// // So that the map.get(&1) doesn't return Some(&100). + /// assert_eq!(map.get(&1), Some(&1)); + /// + /// let some_vec: Vec<_> = vec![(3, 3), (4, 4)]; + /// map.extend(&some_vec); + /// + /// let some_arr = [(5, 5), (6, 6)]; + /// map.extend(&some_arr); + /// + /// let mut vec: Vec<_> = map.into_iter().collect(); + /// // The `IntoIter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: T) { + self.extend(iter.into_iter().map(|&(key, value)| (key, value))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, &(k, v): &'a (K, V)) { + self.insert(k, v); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(K, V)>::extend_reserve(self, additional); + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { + v + } + fn map_val<'new>(v: HashMap) -> HashMap { + v + } + fn iter_key<'a, 'new>(v: Iter<'a, &'static str, u8>) -> Iter<'a, &'new str, u8> { + v + } + fn iter_val<'a, 'new>(v: Iter<'a, u8, &'static str>) -> Iter<'a, u8, &'new str> { + v + } + fn into_iter_key<'new, A: Allocator>( + v: IntoIter<&'static str, u8, A>, + ) -> IntoIter<&'new str, u8, A> { + v + } + fn into_iter_val<'new, A: Allocator>( + v: IntoIter, + ) -> IntoIter { + v + } + fn keys_key<'a, 'new>(v: Keys<'a, &'static str, u8>) -> Keys<'a, &'new str, u8> { + v + } + fn keys_val<'a, 'new>(v: Keys<'a, u8, &'static str>) -> Keys<'a, u8, &'new str> { + v + } + fn values_key<'a, 'new>(v: Values<'a, &'static str, u8>) -> Values<'a, &'new str, u8> { + v + } + fn values_val<'a, 'new>(v: Values<'a, u8, &'static str>) -> Values<'a, u8, &'new str> { + v + } + fn drain<'new>( + d: Drain<'static, &'static str, &'static str>, + ) -> Drain<'new, &'new str, &'new str> { + d + } +} + +#[cfg(test)] +mod test_map { + use super::DefaultHashBuilder; + use super::Entry::{Occupied, Vacant}; + use super::EntryRef; + use super::{HashMap, RawEntryMut}; + use alloc::string::{String, ToString}; + use alloc::sync::Arc; + use allocator_api2::alloc::{AllocError, Allocator, Global}; + use core::alloc::Layout; + use core::ptr::NonNull; + use core::sync::atomic::{AtomicI8, Ordering}; + use rand::{rngs::SmallRng, Rng, SeedableRng}; + use std::borrow::ToOwned; + use std::cell::RefCell; + use std::usize; + use std::vec::Vec; + + #[test] + fn test_zero_capacities() { + type HM = HashMap; + + let m = HM::new(); + assert_eq!(m.capacity(), 0); + + let m = HM::default(); + assert_eq!(m.capacity(), 0); + + let m = HM::with_hasher(DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity(0); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.insert(1, 1); + m.insert(2, 2); + m.remove(&1); + m.remove(&2); + m.shrink_to_fit(); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.reserve(0); + assert_eq!(m.capacity(), 0); + } + + #[test] + fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + + assert!(m.insert(1, 1).is_none()); + + assert!(m.contains_key(&1)); + assert!(!m.contains_key(&0)); + } + + #[test] + fn test_insert() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&2).unwrap(), 4); + } + + #[test] + fn test_clone() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + #[allow(clippy::redundant_clone)] + let m2 = m.clone(); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + #[test] + fn test_clone_from() { + let mut m = HashMap::new(); + let mut m2 = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + m2.clone_from(&m); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); + } + + thread_local! { static DROP_VECTOR: RefCell> = const { RefCell::new(Vec::new()) } } + + #[derive(Hash, PartialEq, Eq)] + struct Droppable { + k: usize, + } + + impl Droppable { + fn new(k: usize) -> Droppable { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[k] += 1; + }); + + Droppable { k } + } + } + + impl Drop for Droppable { + fn drop(&mut self) { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[self.k] -= 1; + }); + } + } + + impl Clone for Droppable { + fn clone(&self) -> Self { + Droppable::new(self.k) + } + } + + #[test] + fn test_drops() { + DROP_VECTOR.with(|slot| { + *slot.borrow_mut() = vec![0; 200]; + }); + + { + let mut m = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + m.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for i in 0..50 { + let k = Droppable::new(i); + let v = m.remove(&k); + + assert!(v.is_some()); + + DROP_VECTOR.with(|v| { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..50 { + assert_eq!(v.borrow()[i], 0); + assert_eq!(v.borrow()[i + 100], 0); + } + + for i in 50..100 { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + } + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_into_iter_drops() { + DROP_VECTOR.with(|v| { + *v.borrow_mut() = vec![0; 200]; + }); + + let hm = { + let mut hm = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + hm.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + { + let mut half = hm.into_iter().take(50); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for _ in half.by_ref() {} + + DROP_VECTOR.with(|v| { + let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); + + let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); + + assert_eq!(nk, 50); + assert_eq!(nv, 50); + }); + }; + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + } + + #[test] + fn test_empty_remove() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.remove(&0), None); + } + + #[test] + fn test_empty_entry() { + let mut m: HashMap = HashMap::new(); + match m.entry(0) { + Occupied(_) => panic!(), + Vacant(_) => {} + } + assert!(*m.entry(0).or_insert(true)); + assert_eq!(m.len(), 1); + } + + #[test] + fn test_empty_entry_ref() { + let mut m: HashMap = HashMap::new(); + match m.entry_ref("poneyland") { + EntryRef::Occupied(_) => panic!(), + EntryRef::Vacant(_) => {} + } + assert!(*m.entry_ref("poneyland").or_insert(true)); + assert_eq!(m.len(), 1); + } + + #[test] + fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.drain().next(), None); + assert_eq!(m.keys().next(), None); + assert_eq!(m.values().next(), None); + assert_eq!(m.values_mut().next(), None); + assert_eq!(m.iter().next(), None); + assert_eq!(m.iter_mut().next(), None); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_iter().next(), None); + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: takes too long + fn test_lots_of_insertions() { + let mut m = HashMap::new(); + + // Try this a few times to make sure we never screw up the hashmap's + // internal state. + for _ in 0..10 { + assert!(m.is_empty()); + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + + for j in 1..=i { + let r = m.get(&j); + assert_eq!(r, Some(&j)); + } + + for j in i + 1..1001 { + let r = m.get(&j); + assert_eq!(r, None); + } + } + + for i in 1001..2001 { + assert!(!m.contains_key(&i)); + } + + // remove forwards + for i in 1..1001 { + assert!(m.remove(&i).is_some()); + + for j in 1..=i { + assert!(!m.contains_key(&j)); + } + + for j in i + 1..1001 { + assert!(m.contains_key(&j)); + } + } + + for i in 1..1001 { + assert!(!m.contains_key(&i)); + } + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + } + + // remove backwards + for i in (1..1001).rev() { + assert!(m.remove(&i).is_some()); + + for j in i..1001 { + assert!(!m.contains_key(&j)); + } + + for j in 1..i { + assert!(m.contains_key(&j)); + } + } + } + } + + #[test] + fn test_find_mut() { + let mut m = HashMap::new(); + assert!(m.insert(1, 12).is_none()); + assert!(m.insert(2, 8).is_none()); + assert!(m.insert(5, 14).is_none()); + let new = 100; + match m.get_mut(&5) { + None => panic!(), + Some(x) => *x = new, + } + assert_eq!(m.get(&5), Some(&new)); + } + + #[test] + fn test_insert_overwrite() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(1, 3).is_some()); + assert_eq!(*m.get(&1).unwrap(), 3); + } + + #[test] + fn test_insert_conflicts() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(5, 3).is_none()); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&1).unwrap(), 2); + } + + #[test] + fn test_conflict_remove() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(5, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&9).unwrap(), 4); + assert!(m.remove(&1).is_some()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + } + + #[test] + fn test_insert_unique_unchecked() { + let mut map = HashMap::new(); + let (k1, v1) = map.insert_unique_unchecked(10, 11); + assert_eq!((&10, &mut 11), (k1, v1)); + let (k2, v2) = map.insert_unique_unchecked(20, 21); + assert_eq!((&20, &mut 21), (k2, v2)); + assert_eq!(Some(&11), map.get(&10)); + assert_eq!(Some(&21), map.get(&20)); + assert_eq!(None, map.get(&30)); + } + + #[test] + fn test_is_empty() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(!m.is_empty()); + assert!(m.remove(&1).is_some()); + assert!(m.is_empty()); + } + + #[test] + fn test_remove() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove(&1), Some(2)); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_remove_entry() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove_entry(&1), Some((1, 2))); + assert_eq!(m.remove(&1), None); + } + + #[test] + fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let mut observed: u32 = 0; + + for (k, v) in &m { + assert_eq!(*v, *k * 2); + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().copied().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value *= 2; + } + let values: Vec<_> = map.values().copied().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); + } + + #[test] + fn test_into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.into_keys().collect(); + + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); + } + + #[test] + fn test_into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.into_values().collect(); + + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); + } + + #[test] + fn test_find() { + let mut m = HashMap::new(); + assert!(m.get(&1).is_none()); + m.insert(1, 2); + match m.get(&1) { + None => panic!(), + Some(v) => assert_eq!(*v, 2), + } + } + + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(m1 != m2); + + m2.insert(3, 4); + + assert_eq!(m1, m2); + } + + #[test] + fn test_show() { + let mut map = HashMap::new(); + let empty: HashMap = HashMap::new(); + + map.insert(1, 2); + map.insert(3, 4); + + let map_str = format!("{map:?}"); + + assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); + assert_eq!(format!("{empty:?}"), "{}"); + } + + #[test] + fn test_expand() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + + let mut i = 0; + let old_raw_cap = m.raw_capacity(); + while old_raw_cap == m.raw_capacity() { + m.insert(i, i); + i += 1; + } + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + } + + #[test] + fn test_behavior_resize_policy() { + let mut m = HashMap::new(); + + assert_eq!(m.len(), 0); + assert_eq!(m.raw_capacity(), 1); + assert!(m.is_empty()); + + m.insert(0, 0); + m.remove(&0); + assert!(m.is_empty()); + let initial_raw_cap = m.raw_capacity(); + m.reserve(initial_raw_cap); + let raw_cap = m.raw_capacity(); + + assert_eq!(raw_cap, initial_raw_cap * 2); + + let mut i = 0; + for _ in 0..raw_cap * 3 / 4 { + m.insert(i, i); + i += 1; + } + // three quarters full + + assert_eq!(m.len(), i); + assert_eq!(m.raw_capacity(), raw_cap); + + for _ in 0..raw_cap / 4 { + m.insert(i, i); + i += 1; + } + // half full + + let new_raw_cap = m.raw_capacity(); + assert_eq!(new_raw_cap, raw_cap * 2); + + for _ in 0..raw_cap / 2 - 1 { + i -= 1; + m.remove(&i); + assert_eq!(m.raw_capacity(), new_raw_cap); + } + // A little more than one quarter full. + m.shrink_to_fit(); + assert_eq!(m.raw_capacity(), raw_cap); + // again, a little more than half full + for _ in 0..raw_cap / 2 { + i -= 1; + m.remove(&i); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), i); + assert!(!m.is_empty()); + assert_eq!(m.raw_capacity(), initial_raw_cap); + } + + #[test] + fn test_reserve_shrink_to_fit() { + let mut m = HashMap::new(); + m.insert(0, 0); + m.remove(&0); + assert!(m.capacity() >= m.len()); + for i in 0..128 { + m.insert(i, i); + } + m.reserve(256); + + let usable_cap = m.capacity(); + for i in 128..(128 + 256) { + m.insert(i, i); + assert_eq!(m.capacity(), usable_cap); + } + + for i in 100..(128 + 256) { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), 100); + assert!(!m.is_empty()); + assert!(m.capacity() >= m.len()); + + for i in 0..100 { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + m.insert(0, 0); + + assert_eq!(m.len(), 1); + assert!(m.capacity() >= m.len()); + assert_eq!(m.remove(&0), Some(0)); + } + + #[test] + fn test_from_iter() { + let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + + assert_eq!(map.iter().len(), xs.len() - 1); + } + + #[test] + fn test_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_mut_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); + } + + #[test] + fn test_iter_mut_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); + } + + #[test] + fn test_index() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + assert_eq!(map[&2], 1); + } + + #[test] + #[should_panic] + fn test_index_nonexistent() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + #[allow(clippy::no_effect)] // false positive lint + map[&4]; + } + + #[test] + fn test_entry() { + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + // Existing key (insert) + match map.entry(1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get(&1).unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry(2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get(&2).unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry(3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get(&3), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry(10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get(&10).unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_ref() { + let xs = [ + ("One".to_owned(), 10), + ("Two".to_owned(), 20), + ("Three".to_owned(), 30), + ("Four".to_owned(), 40), + ("Five".to_owned(), 50), + ("Six".to_owned(), 60), + ]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + // Existing key (insert) + match map.entry_ref("One") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get("One").unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry_ref("Two") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get("Two").unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry_ref("Three") { + EntryRef::Vacant(_) => unreachable!(), + EntryRef::Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get("Three"), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry_ref("Ten") { + EntryRef::Occupied(_) => unreachable!(), + EntryRef::Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get("Ten").unwrap(), &1000); + assert_eq!(map.len(), 6); + } + + #[test] + fn test_entry_take_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10..10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10..10); + match m.entry(x) { + Vacant(_) => {} + Occupied(e) => { + e.remove(); + } + } + + check(&m); + } + } + + #[test] + fn test_entry_ref_take_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + m.insert(x, ()); + } + + for _ in 0..1000 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + match m.entry_ref(x.as_str()) { + EntryRef::Vacant(_) => {} + EntryRef::Occupied(e) => { + e.remove(); + } + } + + check(&m); + } + } + + #[test] + fn test_extend_ref_k_ref_v() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); + } + + #[test] + #[allow(clippy::needless_borrow)] + fn test_extend_ref_kv_tuple() { + use std::ops::AddAssign; + let mut a = HashMap::new(); + a.insert(0, 0); + + fn create_arr + Copy, const N: usize>(start: T, step: T) -> [(T, T); N] { + let mut outs: [(T, T); N] = [(start, start); N]; + let mut element = step; + outs.iter_mut().skip(1).for_each(|(k, v)| { + *k += element; + *v += element; + element += step; + }); + outs + } + + let for_iter: Vec<_> = (0..100).map(|i| (i, i)).collect(); + let iter = for_iter.iter(); + let vec: Vec<_> = (100..200).map(|i| (i, i)).collect(); + a.extend(iter); + a.extend(&vec); + a.extend(create_arr::(200, 1)); + + assert_eq!(a.len(), 300); + + for item in 0..300 { + assert_eq!(a[&item], item); + } + } + + #[test] + fn test_capacity_not_less_than_len() { + let mut a = HashMap::new(); + let mut item = 0; + + for _ in 0..116 { + a.insert(item, 0); + item += 1; + } + + assert!(a.capacity() > a.len()); + + let free = a.capacity() - a.len(); + for _ in 0..free { + a.insert(item, 0); + item += 1; + } + + assert_eq!(a.len(), a.capacity()); + + // Insert at capacity should cause allocation. + a.insert(item, 0); + assert!(a.capacity() > a.len()); + } + + #[test] + fn test_occupied_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key, value); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry(key) { + Vacant(_) => panic!(), + Occupied(e) => assert_eq!(key, *e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_occupied_entry_ref_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key.to_owned(), value); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry_ref(key) { + EntryRef::Vacant(_) => panic!(), + EntryRef::Occupied(e) => assert_eq!(key, e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_vacant_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry(key) { + Occupied(_) => panic!(), + Vacant(e) => { + assert_eq!(key, *e.key()); + e.insert(value); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_vacant_entry_ref_key() { + let mut a: HashMap = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry_ref(key) { + EntryRef::Occupied(_) => panic!(), + EntryRef::Vacant(e) => { + assert_eq!(key, e.key()); + e.insert(value); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + } + + #[test] + fn test_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).insert(value).replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.entry(key) { + Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + Vacant(_) => panic!(), + }; + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_occupied_entry_ref_replace_entry_with() { + let mut a: HashMap = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry_ref(key).insert(value).replace_entry_with(|k, v| { + assert_eq!(k, key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + EntryRef::Occupied(e) => { + assert_eq!(e.key(), key); + assert_eq!(e.get(), &new_value); + } + EntryRef::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.entry_ref(key) { + EntryRef::Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, key); + assert_eq!(v, new_value); + None + }), + EntryRef::Vacant(_) => panic!(), + }; + + match entry { + EntryRef::Vacant(e) => assert_eq!(e.key(), key), + EntryRef::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).and_replace_entry_with(|_, _| panic!()); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_entry_ref_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry_ref(key).and_replace_entry_with(|_, _| panic!()); + + match entry { + EntryRef::Vacant(e) => assert_eq!(e.key(), key), + EntryRef::Occupied(_) => panic!(), + } + + a.insert(key.to_owned(), value); + + let entry = a.entry_ref(key).and_replace_entry_with(|k, v| { + assert_eq!(k, key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + EntryRef::Occupied(e) => { + assert_eq!(e.key(), key); + assert_eq!(e.get(), &new_value); + } + EntryRef::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a.entry_ref(key).and_replace_entry_with(|k, v| { + assert_eq!(k, key); + assert_eq!(v, new_value); + None + }); + + match entry { + EntryRef::Vacant(e) => assert_eq!(e.key(), key), + EntryRef::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .insert(key, value) + .replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.raw_entry_mut().from_key(&key) { + RawEntryMut::Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + RawEntryMut::Vacant(_) => panic!(), + }; + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|_, _| panic!()); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_replace_entry_with_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10..10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10..10); + m.entry(x).and_replace_entry_with(|_, _| None); + check(&m); + } + } + + #[test] + fn test_replace_entry_ref_with_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = u64::from_le_bytes(*b"testseed"); + SmallRng::seed_from_u64(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + m.insert(x, ()); + } + + for _ in 0..1000 { + let mut x = std::string::String::with_capacity(1); + x.push(rng.gen_range('a'..='z')); + m.entry_ref(x.as_str()).and_replace_entry_with(|_, _| None); + check(&m); + } + } + + #[test] + fn test_retain() { + let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); + + map.retain(|&k, _| k % 2 == 0); + assert_eq!(map.len(), 50); + assert_eq!(map[&2], 20); + assert_eq!(map[&4], 40); + assert_eq!(map[&6], 60); + } + + #[test] + fn test_extract_if() { + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + let drained = map.extract_if(|&k, _| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); + assert_eq!(map.len(), 4); + } + { + let mut map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); + map.extract_if(|&k, _| k % 2 == 0).for_each(drop); + assert_eq!(map.len(), 4); + } + } + + #[test] + #[cfg_attr(miri, ignore)] // FIXME: no OOM signalling (https://github.com/rust-lang/miri/issues/613) + fn test_try_reserve() { + use crate::TryReserveError::{AllocError, CapacityOverflow}; + + const MAX_ISIZE: usize = isize::MAX as usize; + + let mut empty_bytes: HashMap = HashMap::new(); + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(usize::MAX) { + } else { + panic!("usize::MAX should trigger an overflow!"); + } + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_ISIZE) { + } else { + panic!("isize::MAX should trigger an overflow!"); + } + + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_ISIZE / 5) { + } else { + // This may succeed if there is enough free memory. Attempt to + // allocate a few more hashmaps to ensure the allocation will fail. + let mut empty_bytes2: HashMap = HashMap::new(); + let _ = empty_bytes2.try_reserve(MAX_ISIZE / 5); + let mut empty_bytes3: HashMap = HashMap::new(); + let _ = empty_bytes3.try_reserve(MAX_ISIZE / 5); + let mut empty_bytes4: HashMap = HashMap::new(); + if let Err(AllocError { .. }) = empty_bytes4.try_reserve(MAX_ISIZE / 5) { + } else { + panic!("isize::MAX / 5 should trigger an OOM!"); + } + } + } + + #[test] + fn test_raw_entry() { + use super::RawEntryMut::{Occupied, Vacant}; + + let xs = [(1_i32, 10_i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().copied().collect(); + + let compute_hash = |map: &HashMap, k: i32| -> u64 { + super::make_hash::(map.hasher(), &k) + }; + + // Existing key (insert) + match map.raw_entry_mut().from_key(&1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + let hash1 = compute_hash(&map, 1); + assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); + assert_eq!( + map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), + (&1, &100) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), + (&1, &100) + ); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.raw_entry_mut().from_key(&2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + let hash2 = compute_hash(&map, 2); + assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); + assert_eq!( + map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), + (&2, &200) + ); + assert_eq!( + map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), + (&2, &200) + ); + assert_eq!(map.len(), 6); + + // Existing key (take) + let hash3 = compute_hash(&map, 3); + match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove_entry(), (3, 30)); + } + } + assert_eq!(map.raw_entry().from_key(&3), None); + assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); + assert_eq!(map.len(), 5); + + // Nonexistent key (insert) + match map.raw_entry_mut().from_key(&10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); + } + } + assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); + assert_eq!(map.len(), 6); + + // Ensure all lookup methods produce equivalent results. + for k in 0..12 { + let hash = compute_hash(&map, k); + let v = map.get(&k).copied(); + let kv = v.as_ref().map(|v| (&k, v)); + + assert_eq!(map.raw_entry().from_key(&k), kv); + assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + + match map.raw_entry_mut().from_key(&k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_hash(hash, |q| *q == k) { + Occupied(o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + } + } + + #[test] + fn test_key_without_hash_impl() { + #[derive(Debug)] + struct IntWrapper(u64); + + let mut m: HashMap = HashMap::default(); + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 0"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(0, IntWrapper(0), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_none()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let vacant_entry = match m.raw_entry_mut().from_hash(1, |k| k.0 == 1) { + RawEntryMut::Occupied(..) => panic!("Found entry for key 1"), + RawEntryMut::Vacant(e) => e, + }; + vacant_entry.insert_with_hasher(1, IntWrapper(1), (), |k| k.0); + } + { + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_some()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + { + let occupied_entry = match m.raw_entry_mut().from_hash(0, |k| k.0 == 0) { + RawEntryMut::Occupied(e) => e, + RawEntryMut::Vacant(..) => panic!("Couldn't find entry for key 0"), + }; + occupied_entry.remove(); + } + assert!(m.raw_entry().from_hash(0, |k| k.0 == 0).is_none()); + assert!(m.raw_entry().from_hash(1, |k| k.0 == 1).is_some()); + assert!(m.raw_entry().from_hash(2, |k| k.0 == 2).is_none()); + } + + #[test] + #[cfg(feature = "raw")] + fn test_into_iter_refresh() { + #[cfg(miri)] + const N: usize = 32; + #[cfg(not(miri))] + const N: usize = 128; + + let mut rng = rand::thread_rng(); + for n in 0..N { + let mut map = HashMap::new(); + for i in 0..n { + assert!(map.insert(i, 2 * i).is_none()); + } + let hash_builder = map.hasher().clone(); + + let mut it = unsafe { map.table.iter() }; + assert_eq!(it.len(), n); + + let mut i = 0; + let mut left = n; + let mut removed = Vec::new(); + loop { + // occasionally remove some elements + if i < n && rng.gen_bool(0.1) { + let hash_value = super::make_hash(&hash_builder, &i); + + unsafe { + let e = map.table.find(hash_value, |q| q.0.eq(&i)); + if let Some(e) = e { + it.reflect_remove(&e); + let t = map.table.remove(e).0; + removed.push(t); + left -= 1; + } else { + assert!(removed.contains(&(i, 2 * i)), "{i} not in {removed:?}"); + let e = map.table.insert( + hash_value, + (i, 2 * i), + super::make_hasher::<_, usize, _>(&hash_builder), + ); + it.reflect_insert(&e); + if let Some(p) = removed.iter().position(|e| e == &(i, 2 * i)) { + removed.swap_remove(p); + } + left += 1; + } + } + } + + let e = it.next(); + if e.is_none() { + break; + } + assert!(i < n); + let t = unsafe { e.unwrap().as_ref() }; + assert!(!removed.contains(t)); + let (key, value) = t; + assert_eq!(*value, 2 * key); + i += 1; + } + assert!(i <= n); + + // just for safety: + assert_eq!(map.table.len(), left); + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_MAP: HashMap = + HashMap::with_hasher(MyHasher); + + let mut map = EMPTY_MAP; + map.insert(17, "seventeen".to_owned()); + assert_eq!("seventeen", map[&17]); + } + + #[test] + fn test_get_each_mut() { + let mut map = HashMap::new(); + map.insert("foo".to_owned(), 0); + map.insert("bar".to_owned(), 10); + map.insert("baz".to_owned(), 20); + map.insert("qux".to_owned(), 30); + + let xs = map.get_many_mut(["foo", "qux"]); + assert_eq!(xs, Some([&mut 0, &mut 30])); + + let xs = map.get_many_mut(["foo", "dud"]); + assert_eq!(xs, None); + + let xs = map.get_many_mut(["foo", "foo"]); + assert_eq!(xs, None); + + let ys = map.get_many_key_value_mut(["bar", "baz"]); + assert_eq!( + ys, + Some([(&"bar".to_owned(), &mut 10), (&"baz".to_owned(), &mut 20),]), + ); + + let ys = map.get_many_key_value_mut(["bar", "dip"]); + assert_eq!(ys, None); + + let ys = map.get_many_key_value_mut(["baz", "baz"]); + assert_eq!(ys, None); + } + + #[test] + #[should_panic = "panic in drop"] + fn test_clone_from_double_drop() { + #[derive(Clone)] + struct CheckedDrop { + panic_in_drop: bool, + dropped: bool, + } + impl Drop for CheckedDrop { + fn drop(&mut self) { + if self.panic_in_drop { + self.dropped = true; + panic!("panic in drop"); + } + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + const DISARMED: CheckedDrop = CheckedDrop { + panic_in_drop: false, + dropped: false, + }; + const ARMED: CheckedDrop = CheckedDrop { + panic_in_drop: true, + dropped: false, + }; + + let mut map1 = HashMap::new(); + map1.insert(1, DISARMED); + map1.insert(2, DISARMED); + map1.insert(3, DISARMED); + map1.insert(4, DISARMED); + + let mut map2 = HashMap::new(); + map2.insert(1, DISARMED); + map2.insert(2, ARMED); + map2.insert(3, DISARMED); + map2.insert(4, DISARMED); + + map2.clone_from(&map1); + } + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_from_memory_leaks() { + use alloc::vec::Vec; + + struct CheckedClone { + panic_in_clone: bool, + need_drop: Vec, + } + impl Clone for CheckedClone { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + need_drop: self.need_drop.clone(), + } + } + } + let mut map1 = HashMap::new(); + map1.insert( + 1, + CheckedClone { + panic_in_clone: false, + need_drop: vec![0, 1, 2], + }, + ); + map1.insert( + 2, + CheckedClone { + panic_in_clone: false, + need_drop: vec![3, 4, 5], + }, + ); + map1.insert( + 3, + CheckedClone { + panic_in_clone: true, + need_drop: vec![6, 7, 8], + }, + ); + let _map2 = map1.clone(); + } + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl MyAlloc { + fn new(drop_count: Arc) -> Self { + MyAlloc { + _inner: Arc::new(MyAllocInner { drop_count }), + } + } + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + let g = Global; + g.deallocate(ptr, layout) + } + } + + #[test] + fn test_hashmap_into_iter_bug() { + let dropped: Arc = Arc::new(AtomicI8::new(1)); + + { + let mut map = HashMap::with_capacity_in(10, MyAlloc::new(dropped.clone())); + for i in 0..10 { + map.entry(i).or_insert_with(|| "i".to_string()); + } + + for (k, v) in map { + println!("{}, {}", k, v); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + #[derive(Debug)] + struct CheckedCloneDrop { + panic_in_clone: bool, + panic_in_drop: bool, + dropped: bool, + data: T, + } + + impl CheckedCloneDrop { + fn new(panic_in_clone: bool, panic_in_drop: bool, data: T) -> Self { + CheckedCloneDrop { + panic_in_clone, + panic_in_drop, + dropped: false, + data, + } + } + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + panic_in_drop: self.panic_in_drop, + dropped: self.dropped, + data: self.data.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.panic_in_drop { + self.dropped = true; + panic!("panic in drop"); + } + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + /// Return hashmap with predefined distribution of elements. + /// All elements will be located in the same order as elements + /// returned by iterator. + /// + /// This function does not panic, but returns an error as a `String` + /// to distinguish between a test panic and an error in the input data. + fn get_test_map( + iter: I, + mut fun: impl FnMut(u64) -> T, + alloc: A, + ) -> Result, DefaultHashBuilder, A>, String> + where + I: Iterator + Clone + ExactSizeIterator, + A: Allocator, + T: PartialEq + core::fmt::Debug, + { + use crate::scopeguard::guard; + + let mut map: HashMap, _, A> = + HashMap::with_capacity_in(iter.size_hint().0, alloc); + { + let mut guard = guard(&mut map, |map| { + for (_, value) in map.iter_mut() { + value.panic_in_drop = false + } + }); + + let mut count = 0; + // Hash and Key must be equal to each other for controlling the elements placement. + for (panic_in_clone, panic_in_drop) in iter.clone() { + if core::mem::needs_drop::() && panic_in_drop { + return Err(String::from( + "panic_in_drop can be set with a type that doesn't need to be dropped", + )); + } + guard.table.insert( + count, + ( + count, + CheckedCloneDrop::new(panic_in_clone, panic_in_drop, fun(count)), + ), + |(k, _)| *k, + ); + count += 1; + } + + // Let's check that all elements are located as we wanted + let mut check_count = 0; + for ((key, value), (panic_in_clone, panic_in_drop)) in guard.iter().zip(iter) { + if *key != check_count { + return Err(format!( + "key != check_count,\nkey: `{}`,\ncheck_count: `{}`", + key, check_count + )); + } + if value.dropped + || value.panic_in_clone != panic_in_clone + || value.panic_in_drop != panic_in_drop + || value.data != fun(check_count) + { + return Err(format!( + "Value is not equal to expected,\nvalue: `{:?}`,\nexpected: \ + `CheckedCloneDrop {{ panic_in_clone: {}, panic_in_drop: {}, dropped: {}, data: {:?} }}`", + value, panic_in_clone, panic_in_drop, false, fun(check_count) + )); + } + check_count += 1; + } + + if guard.len() != check_count as usize { + return Err(format!( + "map.len() != check_count,\nmap.len(): `{}`,\ncheck_count: `{}`", + guard.len(), + check_count + )); + } + + if count != check_count { + return Err(format!( + "count != check_count,\ncount: `{}`,\ncheck_count: `{}`", + count, check_count + )); + } + core::mem::forget(guard); + } + Ok(map) + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + const ARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + const DISARMED_FLAGS: [bool; 8] = [ + DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + + #[test] + #[should_panic = "panic in clone"] + fn test_clone_memory_leaks_and_double_drop_one() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap>, DefaultHashBuilder, MyAlloc> = + match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // Clone should normally clone a few elements, and then (when the + // clone function panics), deallocate both its own memory, memory + // of `dropped: Arc` and the memory of already cloned + // elements (Vec memory inside CheckedCloneDrop). + let _map2 = map.clone(); + } + } + + #[test] + #[should_panic = "panic in drop"] + fn test_clone_memory_leaks_and_double_drop_two() { + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let map: HashMap, DefaultHashBuilder, _> = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + let mut map2 = match get_test_map( + DISARMED_FLAGS.into_iter().zip(ARMED_FLAGS), + |n| n, + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + // The `clone_from` should try to drop the elements of `map2` without + // double drop and leaking the allocator. Elements that have not been + // dropped leak their memory. + map2.clone_from(&map); + } + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are equal to each other). + #[test] + fn test_catch_panic_clone_from_when_len_is_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + DISARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = + match get_test_map(ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), |n| vec![n * 2], MyAlloc::new(dropped.clone())) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.buckets() != scope_map.table.buckets() { + return format!( + "map.table.buckets() != scope_map.table.buckets(),\nleft: `{}`,\nright: `{}`", + map.table.buckets(), scope_map.table.buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } + + /// We check that we have a working table if the clone operation from another + /// thread ended in a panic (when buckets of maps are not equal to each other). + #[test] + fn test_catch_panic_clone_from_when_len_is_not_equal() { + use std::thread; + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + { + assert_eq!(ARMED_FLAGS.len(), DISARMED_FLAGS.len()); + + let mut map = match get_test_map( + [DISARMED].into_iter().zip([DISARMED]), + |n| vec![n], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => panic!("{msg}"), + }; + + thread::scope(|s| { + let result: thread::ScopedJoinHandle<'_, String> = s.spawn(|| { + let scope_map = match get_test_map( + ARMED_FLAGS.into_iter().zip(DISARMED_FLAGS), + |n| vec![n * 2], + MyAlloc::new(dropped.clone()), + ) { + Ok(map) => map, + Err(msg) => return msg, + }; + if map.table.buckets() == scope_map.table.buckets() { + return format!( + "map.table.buckets() == scope_map.table.buckets(): `{}`", + map.table.buckets() + ); + } + map.clone_from(&scope_map); + "We must fail the cloning!!!".to_owned() + }); + if let Ok(msg) = result.join() { + panic!("{msg}") + } + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(map.len(), 0); + assert_eq!(map.iter().count(), 0); + assert_eq!(unsafe { map.table.iter().count() }, 0); + assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + + for idx in 0..map.table.buckets() { + let idx = idx as u64; + assert!( + map.table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 0); + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/raw/alloc.rs b/third_party/crates/hashbrown-0.14.5/src/raw/alloc.rs new file mode 100644 index 0000000..15299e7 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/raw/alloc.rs @@ -0,0 +1,86 @@ +pub(crate) use self::inner::{do_alloc, Allocator, Global}; + +// Nightly-case. +// Use unstable `allocator_api` feature. +// This is compatible with `allocator-api2` which can be enabled or not. +// This is used when building for `std`. +#[cfg(feature = "nightly")] +mod inner { + use crate::alloc::alloc::Layout; + pub use crate::alloc::alloc::{Allocator, Global}; + use core::ptr::NonNull; + + #[allow(clippy::map_err_ignore)] + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + match alloc.allocate(layout) { + Ok(ptr) => Ok(ptr.as_non_null_ptr()), + Err(_) => Err(()), + } + } +} + +// Basic non-nightly case. +// This uses `allocator-api2` enabled by default. +// If any crate enables "nightly" in `allocator-api2`, +// this will be equivalent to the nightly case, +// since `allocator_api2::alloc::Allocator` would be re-export of +// `core::alloc::Allocator`. +#[cfg(all(not(feature = "nightly"), feature = "allocator-api2"))] +mod inner { + use crate::alloc::alloc::Layout; + pub use allocator_api2::alloc::{Allocator, Global}; + use core::ptr::NonNull; + + #[allow(clippy::map_err_ignore)] + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + match alloc.allocate(layout) { + Ok(ptr) => Ok(ptr.cast()), + Err(_) => Err(()), + } + } +} + +// No-defaults case. +// When building with default-features turned off and +// neither `nightly` nor `allocator-api2` is enabled, +// this will be used. +// Making it impossible to use any custom allocator with collections defined +// in this crate. +// Any crate in build-tree can enable `allocator-api2`, +// or `nightly` without disturbing users that don't want to use it. +#[cfg(not(any(feature = "nightly", feature = "allocator-api2")))] +mod inner { + use crate::alloc::alloc::{alloc, dealloc, Layout}; + use core::ptr::NonNull; + + #[allow(clippy::missing_safety_doc)] // not exposed outside of this crate + pub unsafe trait Allocator { + fn allocate(&self, layout: Layout) -> Result, ()>; + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout); + } + + #[derive(Copy, Clone)] + pub struct Global; + + unsafe impl Allocator for Global { + #[inline] + fn allocate(&self, layout: Layout) -> Result, ()> { + unsafe { NonNull::new(alloc(layout)).ok_or(()) } + } + #[inline] + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + dealloc(ptr.as_ptr(), layout); + } + } + + impl Default for Global { + #[inline] + fn default() -> Self { + Global + } + } + + pub(crate) fn do_alloc(alloc: &A, layout: Layout) -> Result, ()> { + alloc.allocate(layout) + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/raw/bitmask.rs b/third_party/crates/hashbrown-0.14.5/src/raw/bitmask.rs new file mode 100644 index 0000000..6576b3c --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/raw/bitmask.rs @@ -0,0 +1,133 @@ +use super::imp::{ + BitMaskWord, NonZeroBitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE, +}; + +/// A bit mask which contains the result of a `Match` operation on a `Group` and +/// allows iterating through them. +/// +/// The bit mask is arranged so that low-order bits represent lower memory +/// addresses for group match results. +/// +/// For implementation reasons, the bits in the set may be sparsely packed with +/// groups of 8 bits representing one element. If any of these bits are non-zero +/// then this element is considered to true in the mask. If this is the +/// case, `BITMASK_STRIDE` will be 8 to indicate a divide-by-8 should be +/// performed on counts/indices to normalize this difference. `BITMASK_MASK` is +/// similarly a mask of all the actually-used bits. +/// +/// To iterate over a bit mask, it must be converted to a form where only 1 bit +/// is set per element. This is done by applying `BITMASK_ITER_MASK` on the +/// mask bits. +#[derive(Copy, Clone)] +pub(crate) struct BitMask(pub(crate) BitMaskWord); + +#[allow(clippy::use_self)] +impl BitMask { + /// Returns a new `BitMask` with all bits inverted. + #[inline] + #[must_use] + #[allow(dead_code)] + pub(crate) fn invert(self) -> Self { + BitMask(self.0 ^ BITMASK_MASK) + } + + /// Returns a new `BitMask` with the lowest bit removed. + #[inline] + #[must_use] + fn remove_lowest_bit(self) -> Self { + BitMask(self.0 & (self.0 - 1)) + } + + /// Returns whether the `BitMask` has at least one set bit. + #[inline] + pub(crate) fn any_bit_set(self) -> bool { + self.0 != 0 + } + + /// Returns the first set bit in the `BitMask`, if there is one. + #[inline] + pub(crate) fn lowest_set_bit(self) -> Option { + if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { + Some(Self::nonzero_trailing_zeros(nonzero)) + } else { + None + } + } + + /// Returns the number of trailing zeroes in the `BitMask`. + #[inline] + pub(crate) fn trailing_zeros(self) -> usize { + // ARM doesn't have a trailing_zeroes instruction, and instead uses + // reverse_bits (RBIT) + leading_zeroes (CLZ). However older ARM + // versions (pre-ARMv7) don't have RBIT and need to emulate it + // instead. Since we only have 1 bit set in each byte on ARM, we can + // use swap_bytes (REV) + leading_zeroes instead. + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + self.0.swap_bytes().leading_zeros() as usize / BITMASK_STRIDE + } else { + self.0.trailing_zeros() as usize / BITMASK_STRIDE + } + } + + /// Same as above but takes a `NonZeroBitMaskWord`. + #[inline] + fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { + if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { + // SAFETY: A byte-swapped non-zero value is still non-zero. + let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) }; + swapped.leading_zeros() as usize / BITMASK_STRIDE + } else { + nonzero.trailing_zeros() as usize / BITMASK_STRIDE + } + } + + /// Returns the number of leading zeroes in the `BitMask`. + #[inline] + pub(crate) fn leading_zeros(self) -> usize { + self.0.leading_zeros() as usize / BITMASK_STRIDE + } +} + +impl IntoIterator for BitMask { + type Item = usize; + type IntoIter = BitMaskIter; + + #[inline] + fn into_iter(self) -> BitMaskIter { + // A BitMask only requires each element (group of bits) to be non-zero. + // However for iteration we need each element to only contain 1 bit. + BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) + } +} + +/// Iterator over the contents of a `BitMask`, returning the indices of set +/// bits. +#[derive(Copy, Clone)] +pub(crate) struct BitMaskIter(pub(crate) BitMask); + +impl BitMaskIter { + /// Flip the bit in the mask for the entry at the given index. + /// + /// Returns the bit's previous state. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + #[cfg(feature = "raw")] + pub(crate) unsafe fn flip(&mut self, index: usize) -> bool { + // NOTE: The + BITMASK_STRIDE - 1 is to set the high bit. + let mask = 1 << (index * BITMASK_STRIDE + BITMASK_STRIDE - 1); + self.0 .0 ^= mask; + // The bit was set if the bit is now 0. + self.0 .0 & mask == 0 + } +} + +impl Iterator for BitMaskIter { + type Item = usize; + + #[inline] + fn next(&mut self) -> Option { + let bit = self.0.lowest_set_bit()?; + self.0 = self.0.remove_lowest_bit(); + Some(bit) + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/raw/generic.rs b/third_party/crates/hashbrown-0.14.5/src/raw/generic.rs new file mode 100644 index 0000000..c668b06 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/raw/generic.rs @@ -0,0 +1,157 @@ +use super::bitmask::BitMask; +use super::EMPTY; +use core::{mem, ptr}; + +// Use the native word size as the group size. Using a 64-bit group size on +// a 32-bit architecture will just end up being more expensive because +// shifts and multiplies will need to be emulated. + +cfg_if! { + if #[cfg(any( + target_pointer_width = "64", + target_arch = "aarch64", + target_arch = "x86_64", + target_arch = "wasm32", + ))] { + type GroupWord = u64; + type NonZeroGroupWord = core::num::NonZeroU64; + } else { + type GroupWord = u32; + type NonZeroGroupWord = core::num::NonZeroU32; + } +} + +pub(crate) type BitMaskWord = GroupWord; +pub(crate) type NonZeroBitMaskWord = NonZeroGroupWord; +pub(crate) const BITMASK_STRIDE: usize = 8; +// We only care about the highest bit of each byte for the mask. +#[allow(clippy::cast_possible_truncation, clippy::unnecessary_cast)] +pub(crate) const BITMASK_MASK: BitMaskWord = 0x8080_8080_8080_8080_u64 as GroupWord; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Helper function to replicate a byte across a `GroupWord`. +#[inline] +fn repeat(byte: u8) -> GroupWord { + GroupWord::from_ne_bytes([byte; Group::WIDTH]) +} + +/// Abstraction over a group of control bytes which can be scanned in +/// parallel. +/// +/// This implementation uses a word-sized integer. +#[derive(Copy, Clone)] +pub(crate) struct Group(GroupWord); + +// We perform all operations in the native endianness, and convert to +// little-endian just before creating a BitMask. The can potentially +// enable the compiler to eliminate unnecessary byte swaps if we are +// only checking whether a BitMask is empty. +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty bytes, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], + bytes: [u8; Group::WIDTH], + } + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], + bytes: [EMPTY; Group::WIDTH], + }; + &ALIGNED_BYTES.bytes + } + + /// Loads a group of bytes starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const u8) -> Self { + Group(ptr::read_unaligned(ptr.cast())) + } + + /// Loads a group of bytes starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + Group(ptr::read(ptr.cast())) + } + + /// Stores the group of bytes to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + ptr::write(ptr.cast(), self.0); + } + + /// Returns a `BitMask` indicating all bytes in the group which *may* + /// have the given value. + /// + /// This function may return a false positive in certain cases where + /// the byte in the group differs from the searched value only in its + /// lowest bit. This is fine because: + /// - This never happens for `EMPTY` and `DELETED`, only full entries. + /// - The check for key equality will catch these. + /// - This only happens if there is at least 1 true match. + /// - The chance of this happening is very low (< 1% chance per byte). + #[inline] + pub(crate) fn match_byte(self, byte: u8) -> BitMask { + // This algorithm is derived from + // https://graphics.stanford.edu/~seander/bithacks.html##ValueInWord + let cmp = self.0 ^ repeat(byte); + BitMask((cmp.wrapping_sub(repeat(0x01)) & !cmp & repeat(0x80)).to_le()) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + // If the high bit is set, then the byte must be either: + // 1111_1111 (EMPTY) or 1000_0000 (DELETED). + // So we can just check if the top two bits are 1 by ANDing them. + BitMask((self.0 & (self.0 << 1) & repeat(0x80)).to_le()) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + // A byte is EMPTY or DELETED iff the high bit is set + BitMask((self.0 & repeat(0x80)).to_le()) + } + + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub(crate) fn match_full(self) -> BitMask { + self.match_empty_or_deleted().invert() + } + + /// Performs the following transformation on all bytes in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let full = 1000_0000 (true) or 0000_0000 (false) + // !1000_0000 + 1 = 0111_1111 + 1 = 1000_0000 (no carry) + // !0000_0000 + 0 = 1111_1111 + 0 = 1111_1111 (no carry) + let full = !self.0 & repeat(0x80); + Group(!full + (full >> 7)) + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/raw/mod.rs b/third_party/crates/hashbrown-0.14.5/src/raw/mod.rs new file mode 100644 index 0000000..c8e8e29 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/raw/mod.rs @@ -0,0 +1,4817 @@ +use crate::alloc::alloc::{handle_alloc_error, Layout}; +use crate::scopeguard::{guard, ScopeGuard}; +use crate::TryReserveError; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::mem::MaybeUninit; +use core::ptr::NonNull; +use core::{hint, ptr}; + +cfg_if! { + // Use the SSE2 implementation if possible: it allows us to scan 16 buckets + // at once instead of 8. We don't bother with AVX since it would require + // runtime dispatch and wouldn't gain us much anyways: the probability of + // finding a match drops off drastically after the first few buckets. + // + // I attempted an implementation on ARM using NEON instructions, but it + // turns out that most NEON instructions have multi-cycle latency, which in + // the end outweighs any gains over the generic implementation. + if #[cfg(all( + target_feature = "sse2", + any(target_arch = "x86", target_arch = "x86_64"), + not(miri), + ))] { + mod sse2; + use sse2 as imp; + } else if #[cfg(all( + target_arch = "aarch64", + target_feature = "neon", + // NEON intrinsics are currently broken on big-endian targets. + // See https://github.com/rust-lang/stdarch/issues/1484. + target_endian = "little", + not(miri), + ))] { + mod neon; + use neon as imp; + } else { + mod generic; + use generic as imp; + } +} + +mod alloc; +pub(crate) use self::alloc::{do_alloc, Allocator, Global}; + +mod bitmask; + +use self::bitmask::BitMaskIter; +use self::imp::Group; + +// Branch prediction hint. This is currently only available on nightly but it +// consistently improves performance by 10-15%. +#[cfg(not(feature = "nightly"))] +use core::convert::identity as likely; +#[cfg(not(feature = "nightly"))] +use core::convert::identity as unlikely; +#[cfg(feature = "nightly")] +use core::intrinsics::{likely, unlikely}; + +// FIXME: use strict provenance functions once they are stable. +// Implement it with a transmute for now. +#[inline(always)] +#[allow(clippy::useless_transmute)] // clippy is wrong, cast and transmute are different here +fn invalid_mut(addr: usize) -> *mut T { + unsafe { core::mem::transmute(addr) } +} + +#[inline] +unsafe fn offset_from(to: *const T, from: *const T) -> usize { + to.offset_from(from) as usize +} + +/// Whether memory allocation errors should return an error or abort. +#[derive(Copy, Clone)] +enum Fallibility { + Fallible, + Infallible, +} + +impl Fallibility { + /// Error to return on capacity overflow. + #[cfg_attr(feature = "inline-more", inline)] + fn capacity_overflow(self) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::CapacityOverflow, + Fallibility::Infallible => panic!("Hash table capacity overflow"), + } + } + + /// Error to return on allocation error. + #[cfg_attr(feature = "inline-more", inline)] + fn alloc_err(self, layout: Layout) -> TryReserveError { + match self { + Fallibility::Fallible => TryReserveError::AllocError { layout }, + Fallibility::Infallible => handle_alloc_error(layout), + } + } +} + +trait SizedTypeProperties: Sized { + const IS_ZERO_SIZED: bool = mem::size_of::() == 0; + const NEEDS_DROP: bool = mem::needs_drop::(); +} + +impl SizedTypeProperties for T {} + +/// Control byte value for an empty bucket. +const EMPTY: u8 = 0b1111_1111; + +/// Control byte value for a deleted bucket. +const DELETED: u8 = 0b1000_0000; + +/// Checks whether a control byte represents a full bucket (top bit is clear). +#[inline] +fn is_full(ctrl: u8) -> bool { + ctrl & 0x80 == 0 +} + +/// Checks whether a control byte represents a special value (top bit is set). +#[inline] +fn is_special(ctrl: u8) -> bool { + ctrl & 0x80 != 0 +} + +/// Checks whether a special control value is EMPTY (just check 1 bit). +#[inline] +fn special_is_empty(ctrl: u8) -> bool { + debug_assert!(is_special(ctrl)); + ctrl & 0x01 != 0 +} + +/// Primary hash function, used to select the initial bucket to probe from. +#[inline] +#[allow(clippy::cast_possible_truncation)] +fn h1(hash: u64) -> usize { + // On 32-bit platforms we simply ignore the higher hash bits. + hash as usize +} + +// Constant for h2 function that grabing the top 7 bits of the hash. +const MIN_HASH_LEN: usize = if mem::size_of::() < mem::size_of::() { + mem::size_of::() +} else { + mem::size_of::() +}; + +/// Secondary hash function, saved in the low 7 bits of the control byte. +#[inline] +#[allow(clippy::cast_possible_truncation)] +fn h2(hash: u64) -> u8 { + // Grab the top 7 bits of the hash. While the hash is normally a full 64-bit + // value, some hash functions (such as FxHash) produce a usize result + // instead, which means that the top 32 bits are 0 on 32-bit platforms. + // So we use MIN_HASH_LEN constant to handle this. + let top7 = hash >> (MIN_HASH_LEN * 8 - 7); + (top7 & 0x7f) as u8 // truncation +} + +/// Probe sequence based on triangular numbers, which is guaranteed (since our +/// table size is a power of two) to visit every group of elements exactly once. +/// +/// A triangular probe has us jump by 1 more group every time. So first we +/// jump by 1 group (meaning we just continue our linear scan), then 2 groups +/// (skipping over 1 group), then 3 groups (skipping over 2 groups), and so on. +/// +/// Proof that the probe will visit every group in the table: +/// +struct ProbeSeq { + pos: usize, + stride: usize, +} + +impl ProbeSeq { + #[inline] + fn move_next(&mut self, bucket_mask: usize) { + // We should have found an empty bucket by now and ended the probe. + debug_assert!( + self.stride <= bucket_mask, + "Went past end of probe sequence" + ); + + self.stride += Group::WIDTH; + self.pos += self.stride; + self.pos &= bucket_mask; + } +} + +/// Returns the number of buckets needed to hold the given number of items, +/// taking the maximum load factor into account. +/// +/// Returns `None` if an overflow occurs. +// Workaround for emscripten bug emscripten-core/emscripten-fastcomp#258 +#[cfg_attr(target_os = "emscripten", inline(never))] +#[cfg_attr(not(target_os = "emscripten"), inline)] +fn capacity_to_buckets(cap: usize) -> Option { + debug_assert_ne!(cap, 0); + + // For small tables we require at least 1 empty bucket so that lookups are + // guaranteed to terminate if an element doesn't exist in the table. + if cap < 8 { + // We don't bother with a table size of 2 buckets since that can only + // hold a single element. Instead we skip directly to a 4 bucket table + // which can hold 3 elements. + return Some(if cap < 4 { 4 } else { 8 }); + } + + // Otherwise require 1/8 buckets to be empty (87.5% load) + // + // Be careful when modifying this, calculate_layout relies on the + // overflow check here. + let adjusted_cap = cap.checked_mul(8)? / 7; + + // Any overflows will have been caught by the checked_mul. Also, any + // rounding errors from the division above will be cleaned up by + // next_power_of_two (which can't overflow because of the previous division). + Some(adjusted_cap.next_power_of_two()) +} + +/// Returns the maximum effective capacity for the given bucket mask, taking +/// the maximum load factor into account. +#[inline] +fn bucket_mask_to_capacity(bucket_mask: usize) -> usize { + if bucket_mask < 8 { + // For tables with 1/2/4/8 buckets, we always reserve one empty slot. + // Keep in mind that the bucket mask is one less than the bucket count. + bucket_mask + } else { + // For larger tables we reserve 12.5% of the slots as empty. + ((bucket_mask + 1) / 8) * 7 + } +} + +/// Helper which allows the max calculation for ctrl_align to be statically computed for each T +/// while keeping the rest of `calculate_layout_for` independent of `T` +#[derive(Copy, Clone)] +struct TableLayout { + size: usize, + ctrl_align: usize, +} + +impl TableLayout { + #[inline] + const fn new() -> Self { + let layout = Layout::new::(); + Self { + size: layout.size(), + ctrl_align: if layout.align() > Group::WIDTH { + layout.align() + } else { + Group::WIDTH + }, + } + } + + #[inline] + fn calculate_layout_for(self, buckets: usize) -> Option<(Layout, usize)> { + debug_assert!(buckets.is_power_of_two()); + + let TableLayout { size, ctrl_align } = self; + // Manual layout calculation since Layout methods are not yet stable. + let ctrl_offset = + size.checked_mul(buckets)?.checked_add(ctrl_align - 1)? & !(ctrl_align - 1); + let len = ctrl_offset.checked_add(buckets + Group::WIDTH)?; + + // We need an additional check to ensure that the allocation doesn't + // exceed `isize::MAX` (https://github.com/rust-lang/rust/pull/95295). + if len > isize::MAX as usize - (ctrl_align - 1) { + return None; + } + + Some(( + unsafe { Layout::from_size_align_unchecked(len, ctrl_align) }, + ctrl_offset, + )) + } +} + +/// A reference to an empty bucket into which an can be inserted. +pub struct InsertSlot { + index: usize, +} + +/// A reference to a hash table bucket containing a `T`. +/// +/// This is usually just a pointer to the element itself. However if the element +/// is a ZST, then we instead track the index of the element in the table so +/// that `erase` works properly. +pub struct Bucket { + // Actually it is pointer to next element than element itself + // this is needed to maintain pointer arithmetic invariants + // keeping direct pointer to element introduces difficulty. + // Using `NonNull` for variance and niche layout + ptr: NonNull, +} + +// This Send impl is needed for rayon support. This is safe since Bucket is +// never exposed in a public API. +unsafe impl Send for Bucket {} + +impl Clone for Bucket { + #[inline] + fn clone(&self) -> Self { + Self { ptr: self.ptr } + } +} + +impl Bucket { + /// Creates a [`Bucket`] that contain pointer to the data. + /// The pointer calculation is performed by calculating the + /// offset from given `base` pointer (convenience for + /// `base.as_ptr().sub(index)`). + /// + /// `index` is in units of `T`; e.g., an `index` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// If the `T` is a ZST, then we instead track the index of the element + /// in the table so that `erase` works properly (return + /// `NonNull::new_unchecked((index + 1) as *mut T)`) + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and the safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for the [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * the `base` pointer must not be `dangling` and must points to the + /// end of the first `value element` from the `data part` of the table, i.e. + /// must be the pointer that returned by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `index` must not be greater than `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` + /// must be no greater than the number returned by the function + /// [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`<*mut T>::sub`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.sub-1 + /// [`NonNull::new_unchecked`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new_unchecked + /// [`RawTable::data_end`]: crate::raw::RawTable::data_end + /// [`RawTableInner::data_end`]: RawTableInner::data_end + /// [`RawTable::buckets`]: crate::raw::RawTable::buckets + /// [`RawTableInner::buckets`]: RawTableInner::buckets + #[inline] + unsafe fn from_base_index(base: NonNull, index: usize) -> Self { + // If mem::size_of::() != 0 then return a pointer to an `element` in + // the data part of the table (we start counting from "0", so that + // in the expression T[last], the "last" index actually one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"): + // + // `from_base_index(base, 1).as_ptr()` returns a pointer that + // points here in the data part of the table + // (to the start of T1) + // | + // | `base: NonNull` must point here + // | (to the end of T0 or to the start of C0) + // v v + // [Padding], Tlast, ..., |T1|, T0, |C0, C1, ..., Clast + // ^ + // `from_base_index(base, 1)` returns a pointer + // that points here in the data part of the table + // (to the end of T1) + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes + // or metadata for data. + let ptr = if T::IS_ZERO_SIZED { + // won't overflow because index must be less than length (bucket_mask) + // and bucket_mask is guaranteed to be less than `isize::MAX` + // (see TableLayout::calculate_layout_for method) + invalid_mut(index + 1) + } else { + base.as_ptr().sub(index) + }; + Self { + ptr: NonNull::new_unchecked(ptr), + } + } + + /// Calculates the index of a [`Bucket`] as distance between two pointers + /// (convenience for `base.as_ptr().offset_from(self.ptr.as_ptr()) as usize`). + /// The returned value is in units of T: the distance in bytes divided by + /// [`core::mem::size_of::()`]. + /// + /// If the `T` is a ZST, then we return the index of the element in + /// the table so that `erase` works properly (return `self.ptr.as_ptr() as usize - 1`). + /// + /// This function is the inverse of [`from_base_index`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*const T>::offset_from`] method of `*const T`. + /// + /// Thus, in order to uphold the safety contracts for [`<*const T>::offset_from`] + /// method, as well as for the correct logic of the work of this crate, the + /// following rules are necessary and sufficient: + /// + /// * `base` contained pointer must not be `dangling` and must point to the + /// end of the first `element` from the `data part` of the table, i.e. + /// must be a pointer that returns by [`RawTable::data_end`] or by + /// [`RawTableInner::data_end`]; + /// + /// * `self` also must not contain dangling pointer; + /// + /// * both `self` and `base` must be created from the same [`RawTable`] + /// (or [`RawTableInner`]). + /// + /// If `mem::size_of::() == 0`, this function is always safe. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`from_base_index`]: crate::raw::Bucket::from_base_index + /// [`RawTable::data_end`]: crate::raw::RawTable::data_end + /// [`RawTableInner::data_end`]: RawTableInner::data_end + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTableInner`]: RawTableInner + /// [`<*const T>::offset_from`]: https://doc.rust-lang.org/nightly/core/primitive.pointer.html#method.offset_from + #[inline] + unsafe fn to_base_index(&self, base: NonNull) -> usize { + // If mem::size_of::() != 0 then return an index under which we used to store the + // `element` in the data part of the table (we start counting from "0", so + // that in the expression T[last], the "last" index actually is one less than the + // "buckets" number in the table, i.e. "last = RawTableInner.bucket_mask"). + // For example for 5th element in table calculation is performed like this: + // + // mem::size_of::() + // | + // | `self = from_base_index(base, 5)` that returns pointer + // | that points here in tha data part of the table + // | (to the end of T5) + // | | `base: NonNull` must point here + // v | (to the end of T0 or to the start of C0) + // /???\ v v + // [Padding], Tlast, ..., |T10|, ..., T5|, T4, T3, T2, T1, T0, |C0, C1, C2, C3, C4, C5, ..., C10, ..., Clast + // \__________ __________/ + // \/ + // `bucket.to_base_index(base)` = 5 + // (base.as_ptr() as usize - self.ptr.as_ptr() as usize) / mem::size_of::() + // + // where: T0...Tlast - our stored data; C0...Clast - control bytes or metadata for data. + if T::IS_ZERO_SIZED { + // this can not be UB + self.ptr.as_ptr() as usize - 1 + } else { + offset_from(base.as_ptr(), self.ptr.as_ptr()) + } + } + + /// Acquires the underlying raw pointer `*mut T` to `data`. + /// + /// # Note + /// + /// If `T` is not [`Copy`], do not use `*mut T` methods that can cause calling the + /// destructor of `T` (for example the [`<*mut T>::drop_in_place`] method), because + /// for properly dropping the data we also need to clear `data` control bytes. If we + /// drop data, but do not clear `data control byte` it leads to double drop when + /// [`RawTable`] goes out of scope. + /// + /// If you modify an already initialized `value`, so [`Hash`] and [`Eq`] on the new + /// `T` value and its borrowed form *must* match those for the old `T` value, as the map + /// will not re-evaluate where the new value should go, meaning the value may become + /// "lost" if their location does not reflect their state. + /// + /// [`RawTable`]: crate::raw::RawTable + /// [`<*mut T>::drop_in_place`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.drop_in_place + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "raw")] + /// # fn test() { + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::raw::{Bucket, RawTable}; + /// + /// type NewHashBuilder = core::hash::BuildHasherDefault; + /// + /// fn make_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash_builder = NewHashBuilder::default(); + /// let mut table = RawTable::new(); + /// + /// let value = ("a", 100); + /// let hash = make_hash(&hash_builder, &value.0); + /// + /// table.insert(hash, value.clone(), |val| make_hash(&hash_builder, &val.0)); + /// + /// let bucket: Bucket<(&str, i32)> = table.find(hash, |(k1, _)| k1 == &value.0).unwrap(); + /// + /// assert_eq!(unsafe { &*bucket.as_ptr() }, &("a", 100)); + /// # } + /// # fn main() { + /// # #[cfg(feature = "raw")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn as_ptr(&self) -> *mut T { + if T::IS_ZERO_SIZED { + // Just return an arbitrary ZST pointer which is properly aligned + // invalid pointer is good enough for ZST + invalid_mut(mem::align_of::()) + } else { + unsafe { self.ptr.as_ptr().sub(1) } + } + } + + /// Create a new [`Bucket`] that is offset from the `self` by the given + /// `offset`. The pointer calculation is performed by calculating the + /// offset from `self` pointer (convenience for `self.ptr.as_ptr().sub(offset)`). + /// This function is used for iterators. + /// + /// `offset` is in units of `T`; e.g., a `offset` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived + /// from the safety rules for [`<*mut T>::sub`] method of `*mut T` and safety + /// rules of [`NonNull::new_unchecked`] function. + /// + /// Thus, in order to uphold the safety contracts for [`<*mut T>::sub`] method + /// and [`NonNull::new_unchecked`] function, as well as for the correct + /// logic of the work of this crate, the following rules are necessary and + /// sufficient: + /// + /// * `self` contained pointer must not be `dangling`; + /// + /// * `self.to_base_index() + ofset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + ofset) <= RawTableInner.bucket_mask` or, in other + /// words, `self.to_base_index() + ofset + 1` must be no greater than the number returned + /// by the function [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the + /// `self.to_base_index() + ofset` must not be greater than `RawTableInner.bucket_mask`, + /// i.e. `(self.to_base_index() + ofset) <= RawTableInner.bucket_mask` or, in other words, + /// `self.to_base_index() + ofset + 1` must be no greater than the number returned by the + /// function [`RawTable::buckets`] or [`RawTableInner::buckets`]. + /// + /// [`Bucket`]: crate::raw::Bucket + /// [`<*mut T>::sub`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.sub-1 + /// [`NonNull::new_unchecked`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.new_unchecked + /// [`RawTable::buckets`]: crate::raw::RawTable::buckets + /// [`RawTableInner::buckets`]: RawTableInner::buckets + #[inline] + unsafe fn next_n(&self, offset: usize) -> Self { + let ptr = if T::IS_ZERO_SIZED { + // invalid pointer is good enough for ZST + invalid_mut(self.ptr.as_ptr() as usize + offset) + } else { + self.ptr.as_ptr().sub(offset) + }; + Self { + ptr: NonNull::new_unchecked(ptr), + } + } + + /// Executes the destructor (if any) of the pointed-to `data`. + /// + /// # Safety + /// + /// See [`ptr::drop_in_place`] for safety concerns. + /// + /// You should use [`RawTable::erase`] instead of this function, + /// or be careful with calling this function directly, because for + /// properly dropping the data we need also clear `data` control bytes. + /// If we drop data, but do not erase `data control byte` it leads to + /// double drop when [`RawTable`] goes out of scope. + /// + /// [`ptr::drop_in_place`]: https://doc.rust-lang.org/core/ptr/fn.drop_in_place.html + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTable::erase`]: crate::raw::RawTable::erase + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) unsafe fn drop(&self) { + self.as_ptr().drop_in_place(); + } + + /// Reads the `value` from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// # Safety + /// + /// See [`ptr::read`] for safety concerns. + /// + /// You should use [`RawTable::remove`] instead of this function, + /// or be careful with calling this function directly, because compiler + /// calls its destructor when readed `value` goes out of scope. It + /// can cause double dropping when [`RawTable`] goes out of scope, + /// because of not erased `data control byte`. + /// + /// [`ptr::read`]: https://doc.rust-lang.org/core/ptr/fn.read.html + /// [`RawTable`]: crate::raw::RawTable + /// [`RawTable::remove`]: crate::raw::RawTable::remove + #[inline] + pub(crate) unsafe fn read(&self) -> T { + self.as_ptr().read() + } + + /// Overwrites a memory location with the given `value` without reading + /// or dropping the old value (like [`ptr::write`] function). + /// + /// # Safety + /// + /// See [`ptr::write`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`ptr::write`]: https://doc.rust-lang.org/core/ptr/fn.write.html + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + #[inline] + pub(crate) unsafe fn write(&self, val: T) { + self.as_ptr().write(val); + } + + /// Returns a shared immutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_ref`] for safety concerns. + /// + /// [`NonNull::as_ref`]: https://doc.rust-lang.org/core/ptr/struct.NonNull.html#method.as_ref + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "raw")] + /// # fn test() { + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::raw::{Bucket, RawTable}; + /// + /// type NewHashBuilder = core::hash::BuildHasherDefault; + /// + /// fn make_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash_builder = NewHashBuilder::default(); + /// let mut table = RawTable::new(); + /// + /// let value: (&str, String) = ("A pony", "is a small horse".to_owned()); + /// let hash = make_hash(&hash_builder, &value.0); + /// + /// table.insert(hash, value.clone(), |val| make_hash(&hash_builder, &val.0)); + /// + /// let bucket: Bucket<(&str, String)> = table.find(hash, |(k, _)| k == &value.0).unwrap(); + /// + /// assert_eq!( + /// unsafe { bucket.as_ref() }, + /// &("A pony", "is a small horse".to_owned()) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "raw")] + /// # test() + /// # } + /// ``` + #[inline] + pub unsafe fn as_ref<'a>(&self) -> &'a T { + &*self.as_ptr() + } + + /// Returns a unique mutable reference to the `value`. + /// + /// # Safety + /// + /// See [`NonNull::as_mut`] for safety concerns. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`NonNull::as_mut`]: https://doc.rust-lang.org/core/ptr/struct.NonNull.html#method.as_mut + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "raw")] + /// # fn test() { + /// use core::hash::{BuildHasher, Hash}; + /// use hashbrown::raw::{Bucket, RawTable}; + /// + /// type NewHashBuilder = core::hash::BuildHasherDefault; + /// + /// fn make_hash(hash_builder: &S, key: &K) -> u64 { + /// use core::hash::Hasher; + /// let mut state = hash_builder.build_hasher(); + /// key.hash(&mut state); + /// state.finish() + /// } + /// + /// let hash_builder = NewHashBuilder::default(); + /// let mut table = RawTable::new(); + /// + /// let value: (&str, String) = ("A pony", "is a small horse".to_owned()); + /// let hash = make_hash(&hash_builder, &value.0); + /// + /// table.insert(hash, value.clone(), |val| make_hash(&hash_builder, &val.0)); + /// + /// let bucket: Bucket<(&str, String)> = table.find(hash, |(k, _)| k == &value.0).unwrap(); + /// + /// unsafe { + /// bucket + /// .as_mut() + /// .1 + /// .push_str(" less than 147 cm at the withers") + /// }; + /// assert_eq!( + /// unsafe { bucket.as_ref() }, + /// &( + /// "A pony", + /// "is a small horse less than 147 cm at the withers".to_owned() + /// ) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "raw")] + /// # test() + /// # } + /// ``` + #[inline] + pub unsafe fn as_mut<'a>(&self) -> &'a mut T { + &mut *self.as_ptr() + } + + /// Copies `size_of` bytes from `other` to `self`. The source + /// and destination may *not* overlap. + /// + /// # Safety + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns. + /// + /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of + /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values + /// in the region beginning at `*self` and the region beginning at `*other` can + /// [violate memory safety]. + /// + /// # Note + /// + /// [`Hash`] and [`Eq`] on the new `T` value and its borrowed form *must* match + /// those for the old `T` value, as the map will not re-evaluate where the new + /// value should go, meaning the value may become "lost" if their location + /// does not reflect their state. + /// + /// [`ptr::copy_nonoverlapping`]: https://doc.rust-lang.org/core/ptr/fn.copy_nonoverlapping.html + /// [`read`]: https://doc.rust-lang.org/core/ptr/fn.read.html + /// [violate memory safety]: https://doc.rust-lang.org/std/ptr/fn.read.html#ownership-of-the-returned-value + /// [`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html + /// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html + #[cfg(feature = "raw")] + #[inline] + pub unsafe fn copy_from_nonoverlapping(&self, other: &Self) { + self.as_ptr().copy_from_nonoverlapping(other.as_ptr(), 1); + } +} + +/// A raw hash table with an unsafe API. +pub struct RawTable { + table: RawTableInner, + alloc: A, + // Tell dropck that we own instances of T. + marker: PhantomData, +} + +/// Non-generic part of `RawTable` which allows functions to be instantiated only once regardless +/// of how many different key-value types are used. +struct RawTableInner { + // Mask to get an index from a hash value. The value is one less than the + // number of buckets in the table. + bucket_mask: usize, + + // [Padding], T1, T2, ..., Tlast, C1, C2, ... + // ^ points here + ctrl: NonNull, + + // Number of elements that can be inserted before we need to grow the table + growth_left: usize, + + // Number of elements in the table, only really used by len() + items: usize, +} + +impl RawTable { + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + pub const fn new() -> Self { + Self { + table: RawTableInner::NEW, + alloc: Global, + marker: PhantomData, + } + } + + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating. + #[cfg(feature = "raw")] + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_capacity_in(capacity, Global) + } + + /// Allocates a new hash table with at least enough capacity for inserting + /// the given number of elements without reallocating. + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_in(capacity, Global) + } +} + +impl RawTable { + const TABLE_LAYOUT: TableLayout = TableLayout::new::(); + + /// Creates a new empty hash table without allocating any memory, using the + /// given allocator. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never written to + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + pub const fn new_in(alloc: A) -> Self { + Self { + table: RawTableInner::NEW, + alloc, + marker: PhantomData, + } + } + + /// Allocates a new hash table with the given number of buckets. + /// + /// The control bytes are left uninitialized. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: A, + buckets: usize, + fallibility: Fallibility, + ) -> Result { + debug_assert!(buckets.is_power_of_two()); + + Ok(Self { + table: RawTableInner::new_uninitialized( + &alloc, + Self::TABLE_LAYOUT, + buckets, + fallibility, + )?, + alloc, + marker: PhantomData, + }) + } + + /// Attempts to allocate a new hash table using the given allocator, with at least enough + /// capacity for inserting the given number of elements without reallocating. + #[cfg(feature = "raw")] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Ok(Self { + table: RawTableInner::fallible_with_capacity( + &alloc, + Self::TABLE_LAYOUT, + capacity, + Fallibility::Fallible, + )?, + alloc, + marker: PhantomData, + }) + } + + /// Allocates a new hash table using the given allocator, with at least enough capacity for + /// inserting the given number of elements without reallocating. + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + table: RawTableInner::with_capacity(&alloc, Self::TABLE_LAYOUT, capacity), + alloc, + marker: PhantomData, + } + } + + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + &self.alloc + } + + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + pub fn data_end(&self) -> NonNull { + // `self.table.ctrl.cast()` returns pointer that + // points here (to the end of `T0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTable::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + self.table.ctrl.cast() + } + + /// Returns pointer to start of data table. + #[inline] + #[cfg(any(feature = "raw", feature = "nightly"))] + pub unsafe fn data_start(&self) -> NonNull { + NonNull::new_unchecked(self.data_end().as_ptr().wrapping_sub(self.buckets())) + } + + /// Return the information about memory allocated by the table. + /// + /// `RawTable` allocates single memory block to store both data and metadata. + /// This function returns allocation size and alignment and the beginning of the area. + /// These are the arguments which will be passed to `dealloc` when the table is dropped. + /// + /// This function might be useful for memory profiling. + #[inline] + #[cfg(feature = "raw")] + pub fn allocation_info(&self) -> (NonNull, Layout) { + // SAFETY: We use the same `table_layout` that was used to allocate + // this table. + unsafe { self.table.allocation_info_or_zero(Self::TABLE_LAYOUT) } + } + + /// Returns the index of a bucket from a `Bucket`. + #[inline] + pub unsafe fn bucket_index(&self, bucket: &Bucket) -> usize { + bucket.to_base_index(self.data_end()) + } + + /// Returns a pointer to an element in the table. + /// + /// The caller must ensure that the `RawTable` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the caller of this function must observe the + /// following safety rules: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTable::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::buckets`] function, i.e. + /// `(index + 1) <= self.buckets()`. + /// + /// [`RawTable::buckets`]: RawTable::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + pub unsafe fn bucket(&self, index: usize) -> Bucket { + // If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + // (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + // the "buckets" number of our `RawTable`, i.e. "n = RawTable::buckets() - 1"): + // + // `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + // part of the `RawTable`, i.e. to the start of T3 (see `Bucket::as_ptr`) + // | + // | `base = self.data_end()` points here + // | (to the start of CT0 or to the end of T0) + // v v + // [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + // ^ \__________ __________/ + // `table.bucket(3)` returns a pointer that points \/ + // here in the `data` part of the `RawTable` (to additional control bytes + // the end of T3) `m = Group::WIDTH - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`; + // CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + // the heap works properly, even if the result of `h1(hash) & self.table.bucket_mask` + // is equal to `self.table.bucket_mask`). See also `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.table.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.table.bucket_mask = self.buckets() - 1`. + debug_assert_ne!(self.table.bucket_mask, 0); + debug_assert!(index < self.buckets()); + Bucket::from_base_index(self.data_end(), index) + } + + /// Erases an element from the table without dropping it. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn erase_no_drop(&mut self, item: &Bucket) { + let index = self.bucket_index(item); + self.table.erase(index); + } + + /// Erases an element from the table, dropping it in place. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::needless_pass_by_value)] + pub unsafe fn erase(&mut self, item: Bucket) { + // Erase the element from the table first since drop might panic. + self.erase_no_drop(&item); + item.drop(); + } + + /// Finds and erases an element from the table, dropping it in place. + /// Returns true if an element was found. + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn erase_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> bool { + // Avoid `Option::map` because it bloats LLVM IR. + if let Some(bucket) = self.find(hash, eq) { + unsafe { + self.erase(bucket); + } + true + } else { + false + } + } + + /// Removes an element from the table, returning it. + /// + /// This also returns an `InsertSlot` pointing to the newly free bucket. + #[cfg_attr(feature = "inline-more", inline)] + #[allow(clippy::needless_pass_by_value)] + pub unsafe fn remove(&mut self, item: Bucket) -> (T, InsertSlot) { + self.erase_no_drop(&item); + ( + item.read(), + InsertSlot { + index: self.bucket_index(&item), + }, + ) + } + + /// Finds and removes an element from the table, returning it. + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { self.remove(bucket).0 }), + None => None, + } + } + + /// Marks all table buckets as empty without dropping their contents. + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear_no_drop(&mut self) { + self.table.clear_no_drop(); + } + + /// Removes all elements from the table without freeing the backing memory. + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + if self.is_empty() { + // Special case empty table to avoid surprising O(capacity) time. + return; + } + // Ensure that the table is reset even if one of the drops panic + let mut self_ = guard(self, |self_| self_.clear_no_drop()); + unsafe { + // SAFETY: ScopeGuard sets to zero the `items` field of the table + // even in case of panic during the dropping of the elements so + // that there will be no double drop of the elements. + self_.table.drop_elements::(); + } + } + + /// Shrinks the table to fit `max(self.len(), min_size)` elements. + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_size: usize, hasher: impl Fn(&T) -> u64) { + // Calculate the minimal number of elements that we need to reserve + // space for. + let min_size = usize::max(self.table.items, min_size); + if min_size == 0 { + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + return; + } + + // Calculate the number of buckets that we need for this number of + // elements. If the calculation overflows then the requested bucket + // count must be larger than what we have right and nothing needs to be + // done. + let min_buckets = match capacity_to_buckets(min_size) { + Some(buckets) => buckets, + None => return, + }; + + // If we have more buckets than we need, shrink the table. + if min_buckets < self.buckets() { + // Fast path if the table is empty + if self.table.items == 0 { + let new_inner = + RawTableInner::with_capacity(&self.alloc, Self::TABLE_LAYOUT, min_size); + let mut old_inner = mem::replace(&mut self.table, new_inner); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } else { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + unsafe { + // SAFETY: + // 1. We know for sure that `min_size >= self.table.items`. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + if self + .resize(min_size, hasher, Fallibility::Infallible) + .is_err() + { + // SAFETY: The result of calling the `resize` function cannot be an error + // because `fallibility == Fallibility::Infallible. + hint::unreachable_unchecked() + } + } + } + } + } + + /// Ensures that at least `additional` items can be inserted into the table + /// without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + if unlikely(additional > self.table.growth_left) { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + unsafe { + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + if self + .reserve_rehash(additional, hasher, Fallibility::Infallible) + .is_err() + { + // SAFETY: All allocation errors will be caught inside `RawTableInner::reserve_rehash`. + hint::unreachable_unchecked() + } + } + } + } + + /// Tries to ensure that at least `additional` items can be inserted into + /// the table without reallocation. + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + if additional > self.table.growth_left { + // SAFETY: The [`RawTableInner`] must already have properly initialized control + // bytes since we will never expose RawTable::new_uninitialized in a public API. + unsafe { self.reserve_rehash(additional, hasher, Fallibility::Fallible) } + } else { + Ok(()) + } + } + + /// Out-of-line slow path for `reserve` and `try_reserve`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cold] + #[inline(never)] + unsafe fn reserve_rehash( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + unsafe { + // SAFETY: + // 1. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 2. The `drop` function is the actual drop function of the elements stored in + // the table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.table.reserve_rehash_inner( + &self.alloc, + additional, + &|table, index| hasher(table.bucket::(index).as_ref()), + fallibility, + Self::TABLE_LAYOUT, + if T::NEEDS_DROP { + Some(mem::transmute(ptr::drop_in_place:: as unsafe fn(*mut T))) + } else { + None + }, + ) + } + } + + /// Allocates a new table of a different size and moves the contents of the + /// current table into it. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes, + /// otherwise calling this function results in [`undefined behavior`] + /// + /// The caller of this function must ensure that `capacity >= self.table.items` + /// otherwise: + /// + /// * If `self.table.items != 0`, calling of this function with `capacity` + /// equal to 0 (`capacity == 0`) results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) < Group::WIDTH` and + /// `self.table.items > capacity_to_buckets(capacity)` + /// calling this function results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) >= Group::WIDTH` and + /// `self.table.items > capacity_to_buckets(capacity)` + /// calling this function are never return (will go into an + /// infinite loop). + /// + /// See [`RawTableInner::find_insert_slot`] for more information. + /// + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn resize( + &mut self, + capacity: usize, + hasher: impl Fn(&T) -> u64, + fallibility: Fallibility, + ) -> Result<(), TryReserveError> { + // SAFETY: + // 1. The caller of this function guarantees that `capacity >= self.table.items`. + // 2. We know for sure that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.table.resize_inner( + &self.alloc, + capacity, + &|table, index| hasher(table.bucket::(index).as_ref()), + fallibility, + Self::TABLE_LAYOUT, + ) + } + + /// Inserts a new element into the table, and returns its raw bucket. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> Bucket { + unsafe { + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose `RawTable::new_uninitialized` in a public API. + // + // 2. We reserve additional space (if necessary) right after calling this function. + let mut slot = self.table.find_insert_slot(hash); + + // We can avoid growing the table once we have reached our load factor if we are replacing + // a tombstone. This works since the number of EMPTY slots does not change in this case. + // + // SAFETY: The function is guaranteed to return [`InsertSlot`] that contains an index + // in the range `0..=self.buckets()`. + let old_ctrl = *self.table.ctrl(slot.index); + if unlikely(self.table.growth_left == 0 && special_is_empty(old_ctrl)) { + self.reserve(1, hasher); + // SAFETY: We know for sure that `RawTableInner` has control bytes + // initialized and that there is extra space in the table. + slot = self.table.find_insert_slot(hash); + } + + self.insert_in_slot(hash, slot, value) + } + } + + /// Attempts to insert a new element without growing the table and return its raw bucket. + /// + /// Returns an `Err` containing the given element if inserting it would require growing the + /// table. + /// + /// This does not check if the given element already exists in the table. + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_insert_no_grow(&mut self, hash: u64, value: T) -> Result, T> { + unsafe { + match self.table.prepare_insert_no_grow(hash) { + Ok(index) => { + let bucket = self.bucket(index); + bucket.write(value); + Ok(bucket) + } + Err(()) => Err(value), + } + } + } + + /// Inserts a new element into the table, and returns a mutable reference to it. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> &mut T { + unsafe { self.insert(hash, value, hasher).as_mut() } + } + + /// Inserts a new element into the table, without growing the table. + /// + /// There must be enough space in the table to insert the new element. + /// + /// This does not check if the given element already exists in the table. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(any(feature = "raw", feature = "rustc-internal-api"))] + pub unsafe fn insert_no_grow(&mut self, hash: u64, value: T) -> Bucket { + let (index, old_ctrl) = self.table.prepare_insert_slot(hash); + let bucket = self.table.bucket(index); + + // If we are replacing a DELETED entry then we don't need to update + // the load counter. + self.table.growth_left -= special_is_empty(old_ctrl) as usize; + + bucket.write(value); + self.table.items += 1; + bucket + } + + /// Temporary removes a bucket, applying the given function to the removed + /// element and optionally put back the returned value in the same bucket. + /// + /// Returns `true` if the bucket still contains an element + /// + /// This does not check if the given bucket is actually occupied. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn replace_bucket_with(&mut self, bucket: Bucket, f: F) -> bool + where + F: FnOnce(T) -> Option, + { + let index = self.bucket_index(&bucket); + let old_ctrl = *self.table.ctrl(index); + debug_assert!(self.is_bucket_full(index)); + let old_growth_left = self.table.growth_left; + let item = self.remove(bucket).0; + if let Some(new_item) = f(item) { + self.table.growth_left = old_growth_left; + self.table.set_ctrl(index, old_ctrl); + self.table.items += 1; + self.bucket(index).write(new_item); + true + } else { + false + } + } + + /// Searches for an element in the table. If the element is not found, + /// returns `Err` with the position of a slot where an element with the + /// same hash could be inserted. + /// + /// This function may resize the table if additional space is required for + /// inserting an element. + #[inline] + pub fn find_or_find_insert_slot( + &mut self, + hash: u64, + mut eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Result, InsertSlot> { + self.reserve(1, hasher); + + unsafe { + // SAFETY: + // 1. We know for sure that there is at least one empty `bucket` in the table. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since we will + // never expose `RawTable::new_uninitialized` in a public API. + // 3. The `find_or_find_insert_slot_inner` function returns the `index` of only the full bucket, + // which is in the range `0..self.buckets()` (since there is at least one empty `bucket` in + // the table), so calling `self.bucket(index)` and `Bucket::as_ref` is safe. + match self + .table + .find_or_find_insert_slot_inner(hash, &mut |index| eq(self.bucket(index).as_ref())) + { + // SAFETY: See explanation above. + Ok(index) => Ok(self.bucket(index)), + Err(slot) => Err(slot), + } + } + } + + /// Inserts a new element into the table in the given slot, and returns its + /// raw bucket. + /// + /// # Safety + /// + /// `slot` must point to a slot previously returned by + /// `find_or_find_insert_slot`, and no mutation of the table must have + /// occurred since that call. + #[inline] + pub unsafe fn insert_in_slot(&mut self, hash: u64, slot: InsertSlot, value: T) -> Bucket { + let old_ctrl = *self.table.ctrl(slot.index); + self.table.record_item_insert_at(slot.index, old_ctrl, hash); + + let bucket = self.bucket(slot.index); + bucket.write(value); + bucket + } + + /// Searches for an element in the table. + #[inline] + pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option> { + unsafe { + // SAFETY: + // 1. The [`RawTableInner`] must already have properly initialized control bytes since we + // will never expose `RawTable::new_uninitialized` in a public API. + // 1. The `find_inner` function returns the `index` of only the full bucket, which is in + // the range `0..self.buckets()`, so calling `self.bucket(index)` and `Bucket::as_ref` + // is safe. + let result = self + .table + .find_inner(hash, &mut |index| eq(self.bucket(index).as_ref())); + + // Avoid `Option::map` because it bloats LLVM IR. + match result { + // SAFETY: See explanation above. + Some(index) => Some(self.bucket(index)), + None => None, + } + } + } + + /// Gets a reference to an element in the table. + #[inline] + pub fn get(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + /// Gets a mutable reference to an element in the table. + #[inline] + pub fn get_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + // Avoid `Option::map` because it bloats LLVM IR. + match self.find(hash, eq) { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + /// Attempts to get mutable references to `N` entries in the table at once. + /// + /// Returns an array of length `N` with the results of each query. + /// + /// At most one mutable reference will be returned to any entry. `None` will be returned if any + /// of the hashes are duplicates. `None` will be returned if the hash is not found. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + pub fn get_many_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + unsafe { + let ptrs = self.get_many_mut_pointers(hashes, eq)?; + + for (i, &cur) in ptrs.iter().enumerate() { + if ptrs[..i].iter().any(|&prev| ptr::eq::(prev, cur)) { + return None; + } + } + // All bucket are distinct from all previous buckets so we're clear to return the result + // of the lookup. + + // TODO use `MaybeUninit::array_assume_init` here instead once that's stable. + Some(mem::transmute_copy(&ptrs)) + } + } + + pub unsafe fn get_many_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + let ptrs = self.get_many_mut_pointers(hashes, eq)?; + Some(mem::transmute_copy(&ptrs)) + } + + unsafe fn get_many_mut_pointers( + &mut self, + hashes: [u64; N], + mut eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[*mut T; N]> { + // TODO use `MaybeUninit::uninit_array` here instead once that's stable. + let mut outs: MaybeUninit<[*mut T; N]> = MaybeUninit::uninit(); + let outs_ptr = outs.as_mut_ptr(); + + for (i, &hash) in hashes.iter().enumerate() { + let cur = self.find(hash, |k| eq(i, k))?; + *(*outs_ptr).get_unchecked_mut(i) = cur.as_mut(); + } + + // TODO use `MaybeUninit::array_assume_init` here instead once that's stable. + Some(outs.assume_init()) + } + + /// Returns the number of elements the map can hold without reallocating. + /// + /// This number is a lower bound; the table might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + #[inline] + pub fn capacity(&self) -> usize { + self.table.items + self.table.growth_left + } + + /// Returns the number of elements in the table. + #[inline] + pub fn len(&self) -> usize { + self.table.items + } + + /// Returns `true` if the table contains no elements. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns the number of buckets in the table. + #[inline] + pub fn buckets(&self) -> usize { + self.table.bucket_mask + 1 + } + + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + pub unsafe fn is_bucket_full(&self, index: usize) -> bool { + self.table.is_bucket_full(index) + } + + /// Returns an iterator over every element in the table. It is up to + /// the caller to ensure that the `RawTable` outlives the `RawIter`. + /// Because we cannot make the `next` method unsafe on the `RawIter` + /// struct, we have to make the `iter` method unsafe. + #[inline] + pub unsafe fn iter(&self) -> RawIter { + // SAFETY: + // 1. The caller must uphold the safety contract for `iter` method. + // 2. The [`RawTableInner`] must already have properly initialized control bytes since + // we will never expose RawTable::new_uninitialized in a public API. + self.table.iter() + } + + /// Returns an iterator over occupied buckets that could match a given hash. + /// + /// `RawTable` only stores 7 bits of the hash value, so this iterator may + /// return items that have a hash value different than the one provided. You + /// should always validate the returned values before using them. + /// + /// It is up to the caller to ensure that the `RawTable` outlives the + /// `RawIterHash`. Because we cannot make the `next` method unsafe on the + /// `RawIterHash` struct, we have to make the `iter_hash` method unsafe. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "raw")] + pub unsafe fn iter_hash(&self, hash: u64) -> RawIterHash { + RawIterHash::new(self, hash) + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> RawDrain<'_, T, A> { + unsafe { + let iter = self.iter(); + self.drain_iter_from(iter) + } + } + + /// Returns an iterator which removes all elements from the table without + /// freeing the memory. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn drain_iter_from(&mut self, iter: RawIter) -> RawDrain<'_, T, A> { + debug_assert_eq!(iter.len(), self.len()); + RawDrain { + iter, + table: mem::replace(&mut self.table, RawTableInner::NEW), + orig_table: NonNull::from(&mut self.table), + marker: PhantomData, + } + } + + /// Returns an iterator which consumes all elements from the table. + /// + /// Iteration starts at the provided iterator's current location. + /// + /// It is up to the caller to ensure that the iterator is valid for this + /// `RawTable` and covers all items that remain in the table. + pub unsafe fn into_iter_from(self, iter: RawIter) -> RawIntoIter { + debug_assert_eq!(iter.len(), self.len()); + + let allocation = self.into_allocation(); + RawIntoIter { + iter, + allocation, + marker: PhantomData, + } + } + + /// Converts the table into a raw allocation. The contents of the table + /// should be dropped using a `RawIter` before freeing the allocation. + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn into_allocation(self) -> Option<(NonNull, Layout, A)> { + let alloc = if self.table.is_empty_singleton() { + None + } else { + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = + match Self::TABLE_LAYOUT.calculate_layout_for(self.table.buckets()) { + Some(lco) => lco, + None => unsafe { hint::unreachable_unchecked() }, + }; + Some(( + unsafe { NonNull::new_unchecked(self.table.ctrl.as_ptr().sub(ctrl_offset)) }, + layout, + unsafe { ptr::read(&self.alloc) }, + )) + }; + mem::forget(self); + alloc + } +} + +unsafe impl Send for RawTable +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawTable +where + T: Sync, + A: Sync, +{ +} + +impl RawTableInner { + const NEW: Self = RawTableInner::new(); + + /// Creates a new empty hash table without allocating any memory. + /// + /// In effect this returns a table with exactly 1 bucket. However we can + /// leave the data pointer dangling since that bucket is never accessed + /// due to our load factor forcing us to always have at least 1 free bucket. + #[inline] + const fn new() -> Self { + Self { + // Be careful to cast the entire slice to a raw pointer. + ctrl: unsafe { NonNull::new_unchecked(Group::static_empty() as *const _ as *mut u8) }, + bucket_mask: 0, + items: 0, + growth_left: 0, + } + } +} + +impl RawTableInner { + /// Allocates a new [`RawTableInner`] with the given number of buckets. + /// The control bytes and buckets are left uninitialized. + /// + /// # Safety + /// + /// The caller of this function must ensure that the `buckets` is power of two + /// and also initialize all control bytes of the length `self.bucket_mask + 1 + + /// Group::WIDTH` with the [`EMPTY`] bytes. + /// + /// See also [`Allocator`] API for other safety concerns. + /// + /// [`Allocator`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new_uninitialized( + alloc: &A, + table_layout: TableLayout, + buckets: usize, + fallibility: Fallibility, + ) -> Result + where + A: Allocator, + { + debug_assert!(buckets.is_power_of_two()); + + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = match table_layout.calculate_layout_for(buckets) { + Some(lco) => lco, + None => return Err(fallibility.capacity_overflow()), + }; + + let ptr: NonNull = match do_alloc(alloc, layout) { + Ok(block) => block.cast(), + Err(_) => return Err(fallibility.alloc_err(layout)), + }; + + // SAFETY: null pointer will be caught in above check + let ctrl = NonNull::new_unchecked(ptr.as_ptr().add(ctrl_offset)); + Ok(Self { + ctrl, + bucket_mask: buckets - 1, + items: 0, + growth_left: bucket_mask_to_capacity(buckets - 1), + }) + } + + /// Attempts to allocate a new [`RawTableInner`] with at least enough + /// capacity for inserting the given number of elements without reallocating. + /// + /// All the control bytes are initialized with the [`EMPTY`] bytes. + #[inline] + fn fallible_with_capacity( + alloc: &A, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result + where + A: Allocator, + { + if capacity == 0 { + Ok(Self::NEW) + } else { + // SAFETY: We checked that we could successfully allocate the new table, and then + // initialized all control bytes with the constant `EMPTY` byte. + unsafe { + let buckets = + capacity_to_buckets(capacity).ok_or_else(|| fallibility.capacity_overflow())?; + + let result = Self::new_uninitialized(alloc, table_layout, buckets, fallibility)?; + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `self.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. + result.ctrl(0).write_bytes(EMPTY, result.num_ctrl_bytes()); + + Ok(result) + } + } + } + + /// Allocates a new [`RawTableInner`] with at least enough capacity for inserting + /// the given number of elements without reallocating. + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`fallible_with_capacity`] instead if you want to + /// handle memory allocation failure. + /// + /// All the control bytes are initialized with the [`EMPTY`] bytes. + /// + /// [`fallible_with_capacity`]: RawTableInner::fallible_with_capacity + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + fn with_capacity(alloc: &A, table_layout: TableLayout, capacity: usize) -> Self + where + A: Allocator, + { + // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. + match Self::fallible_with_capacity(alloc, table_layout, capacity, Fallibility::Infallible) { + Ok(table_inner) => table_inner, + // SAFETY: All allocation errors will be caught inside `RawTableInner::new_uninitialized`. + Err(_) => unsafe { hint::unreachable_unchecked() }, + } + } + + /// Fixes up an insertion slot returned by the [`RawTableInner::find_insert_slot_in_group`] method. + /// + /// In tables smaller than the group width (`self.buckets() < Group::WIDTH`), trailing control + /// bytes outside the range of the table are filled with [`EMPTY`] entries. These will unfortunately + /// trigger a match of [`RawTableInner::find_insert_slot_in_group`] function. This is because + /// the `Some(bit)` returned by `group.match_empty_or_deleted().lowest_set_bit()` after masking + /// (`(probe_seq.pos + bit) & self.bucket_mask`) may point to a full bucket that is already occupied. + /// We detect this situation here and perform a second scan starting at the beginning of the table. + /// This second scan is guaranteed to find an empty slot (due to the load factor) before hitting the + /// trailing control bytes (containing [`EMPTY`] bytes). + /// + /// If this function is called correctly, it is guaranteed to return [`InsertSlot`] with an + /// index of an empty or deleted bucket in the range `0..self.buckets()` (see `Warning` and + /// `Safety`). + /// + /// # Warning + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise if the table is less than + /// the group width (`self.buckets() < Group::WIDTH`) this function returns an index outside of the + /// table indices range `0..self.buckets()` (`0..=self.bucket_mask`). Attempt to write data at that + /// index will cause immediate [`undefined behavior`]. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::ctrl`] method. + /// Thus, in order to uphold those safety contracts, as well as for the correct logic of the work + /// of this crate, the following rules are necessary and sufficient: + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise calling this + /// function results in [`undefined behavior`]. + /// + /// * This function must only be used on insertion slots found by [`RawTableInner::find_insert_slot_in_group`] + /// (after the `find_insert_slot_in_group` function, but before insertion into the table). + /// + /// * The `index` must not be greater than the `self.bucket_mask`, i.e. `(index + 1) <= self.buckets()` + /// (this one is provided by the [`RawTableInner::find_insert_slot_in_group`] function). + /// + /// Calling this function with an index not provided by [`RawTableInner::find_insert_slot_in_group`] + /// may result in [`undefined behavior`] even if the index satisfies the safety rules of the + /// [`RawTableInner::ctrl`] function (`index < self.bucket_mask + 1 + Group::WIDTH`). + /// + /// [`RawTableInner::ctrl`]: RawTableInner::ctrl + /// [`RawTableInner::find_insert_slot_in_group`]: RawTableInner::find_insert_slot_in_group + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn fix_insert_slot(&self, mut index: usize) -> InsertSlot { + // SAFETY: The caller of this function ensures that `index` is in the range `0..=self.bucket_mask`. + if unlikely(self.is_bucket_full(index)) { + debug_assert!(self.bucket_mask < Group::WIDTH); + // SAFETY: + // + // * Since the caller of this function ensures that the control bytes are properly + // initialized and `ptr = self.ctrl(0)` points to the start of the array of control + // bytes, therefore: `ctrl` is valid for reads, properly aligned to `Group::WIDTH` + // and points to the properly initialized control bytes (see also + // `TableLayout::calculate_layout_for` and `ptr::read`); + // + // * Because the caller of this function ensures that the index was provided by the + // `self.find_insert_slot_in_group()` function, so for for tables larger than the + // group width (self.buckets() >= Group::WIDTH), we will never end up in the given + // branch, since `(probe_seq.pos + bit) & self.bucket_mask` in `find_insert_slot_in_group` + // cannot return a full bucket index. For tables smaller than the group width, calling + // the `unwrap_unchecked` function is also safe, as the trailing control bytes outside + // the range of the table are filled with EMPTY bytes (and we know for sure that there + // is at least one FULL bucket), so this second scan either finds an empty slot (due to + // the load factor) or hits the trailing control bytes (containing EMPTY). + index = Group::load_aligned(self.ctrl(0)) + .match_empty_or_deleted() + .lowest_set_bit() + .unwrap_unchecked(); + } + InsertSlot { index } + } + + /// Finds the position to insert something in a group. + /// + /// **This may have false positives and must be fixed up with `fix_insert_slot` + /// before it's used.** + /// + /// The function is guaranteed to return the index of an empty or deleted [`Bucket`] + /// in the range `0..self.buckets()` (`0..=self.bucket_mask`). + #[inline] + fn find_insert_slot_in_group(&self, group: &Group, probe_seq: &ProbeSeq) -> Option { + let bit = group.match_empty_or_deleted().lowest_set_bit(); + + if likely(bit.is_some()) { + // This is the same as `(probe_seq.pos + bit) % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + Some((probe_seq.pos + bit.unwrap()) & self.bucket_mask) + } else { + None + } + } + + /// Searches for an element in the table, or a potential slot where that element could + /// be inserted (an empty or deleted [`Bucket`] index). + /// + /// This uses dynamic dispatch to reduce the amount of code generated, but that is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element (as `Ok(index)`). If the element is not found and there is at least 1 + /// empty or deleted [`Bucket`] in the table, the function is guaranteed to return + /// [InsertSlot] with an index in the range `0..self.buckets()`, but in any case, + /// if this function returns [`InsertSlot`], it will contain an index in the range + /// `0..=self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// Attempt to write data at the [`InsertSlot`] returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`EMPTY] + /// control bytes outside the table range. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn find_or_find_insert_slot_inner( + &self, + hash: u64, + eq: &mut dyn FnMut(usize) -> bool, + ) -> Result { + let mut insert_slot = None; + + let h2_hash = h2(hash); + let mut probe_seq = self.probe_seq(hash); + + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because mumber of + // buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + for bit in group.match_byte(h2_hash) { + let index = (probe_seq.pos + bit) & self.bucket_mask; + + if likely(eq(index)) { + return Ok(index); + } + } + + // We didn't find the element we were looking for in the group, try to get an + // insertion slot from the group if we don't have one yet. + if likely(insert_slot.is_none()) { + insert_slot = self.find_insert_slot_in_group(&group, &probe_seq); + } + + // Only stop the search if the group contains at least one empty element. + // Otherwise, the element that we are looking for might be in a following group. + if likely(group.match_empty().any_bit_set()) { + // We must have found a insert slot by now, since the current group contains at + // least one. For tables smaller than the group width, there will still be an + // empty element in the current (and only) group due to the load factor. + unsafe { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the slot / index found by `self.find_insert_slot_in_group` + return Err(self.fix_insert_slot(insert_slot.unwrap_unchecked())); + } + } + + probe_seq.move_next(self.bucket_mask); + } + } + + /// Searches for an empty or deleted bucket which is suitable for inserting a new + /// element and sets the hash for that slot. Returns an index of that slot and the + /// old control byte stored in the found index. + /// + /// This function does not check if the given element exists in the table. Also, + /// this function does not check if there is enough space in the table to insert + /// a new element. Caller of the funtion must make ensure that the table has at + /// least 1 empty or deleted `bucket`, otherwise this function will never return + /// (will go into an infinite loop) for tables larger than the group width, or + /// return an index outside of the table indices range if the table is less than + /// the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return an `index` in the range `0..self.buckets()`, but in any case, + /// if this function returns an `index` it will be in the range `0..=self.buckets()`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for the + /// [`RawTableInner::set_ctrl_h2`] and [`RawTableInner::find_insert_slot`] methods. + /// Thus, in order to uphold the safety contracts for that methods, as well as for + /// the correct logic of the work of this crate, you must observe the following rules + /// when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated and has properly initialized + /// control bytes otherwise calling this function results in [`undefined behavior`]. + /// + /// * The caller of this function must ensure that the "data" parts of the table + /// will have an entry in the returned index (matching the given hash) right + /// after calling this function. + /// + /// Attempt to write data at the `index` returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`EMPTY] + /// control bytes outside the table range. + /// + /// The caller must independently increase the `items` field of the table, and also, + /// if the old control byte was [`EMPTY`], then decrease the table's `growth_left` + /// field, and do not change it if the old control byte was [`DELETED`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`RawTableInner::ctrl`]: RawTableInner::ctrl + /// [`RawTableInner::set_ctrl_h2`]: RawTableInner::set_ctrl_h2 + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + #[inline] + unsafe fn prepare_insert_slot(&mut self, hash: u64) -> (usize, u8) { + // SAFETY: Caller of this function ensures that the control bytes are properly initialized. + let index: usize = self.find_insert_slot(hash).index; + // SAFETY: + // 1. The `find_insert_slot` function either returns an `index` less than or + // equal to `self.buckets() = self.bucket_mask + 1` of the table, or never + // returns if it cannot find an empty or deleted slot. + // 2. The caller of this function guarantees that the table has already been + // allocated + let old_ctrl = *self.ctrl(index); + self.set_ctrl_h2(index, hash); + (index, old_ctrl) + } + + /// Searches for an empty or deleted bucket which is suitable for inserting + /// a new element, returning the `index` for the new [`Bucket`]. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty or deleted `bucket`, otherwise this function + /// will never return (will go into an infinite loop) for tables larger than the group + /// width, or return an index outside of the table indices range if the table is less + /// than the group width. + /// + /// If there is at least 1 empty or deleted `bucket` in the table, the function is + /// guaranteed to return [`InsertSlot`] with an index in the range `0..self.buckets()`, + /// but in any case, if this function returns [`InsertSlot`], it will contain an index + /// in the range `0..=self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// Attempt to write data at the [`InsertSlot`] returned by this function when the table is + /// less than the group width and if there was not at least one empty or deleted bucket in + /// the table will cause immediate [`undefined behavior`]. This is because in this case the + /// function will return `self.bucket_mask + 1` as an index due to the trailing [`EMPTY] + /// control bytes outside the table range. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn find_insert_slot(&self, hash: u64) -> InsertSlot { + let mut probe_seq = self.probe_seq(hash); + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask` and also because mumber of + // buckets is a power of two (see `self.probe_seq` function). + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + let index = self.find_insert_slot_in_group(&group, &probe_seq); + if likely(index.is_some()) { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * We use this function with the slot / index found by `self.find_insert_slot_in_group` + unsafe { + return self.fix_insert_slot(index.unwrap_unchecked()); + } + } + probe_seq.move_next(self.bucket_mask); + } + } + + /// Searches for an element in a table, returning the `index` of the found element. + /// This uses dynamic dispatch to reduce the amount of code generated, but it is + /// eliminated by LLVM optimizations. + /// + /// This function does not make any changes to the `data` part of the table, or any + /// changes to the `items` or `growth_left` field of the table. + /// + /// The table must have at least 1 empty `bucket`, otherwise, if the + /// `eq: &mut dyn FnMut(usize) -> bool` function does not return `true`, + /// this function will also never return (will go into an infinite loop). + /// + /// This function is guaranteed to provide the `eq: &mut dyn FnMut(usize) -> bool` + /// function with only `FULL` buckets' indices and return the `index` of the found + /// element as `Some(index)`, so the index will always be in the range + /// `0..self.buckets()`. + /// + /// # Safety + /// + /// The [`RawTableInner`] must have properly initialized control bytes otherwise calling + /// this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn find_inner(&self, hash: u64, eq: &mut dyn FnMut(usize) -> bool) -> Option { + let h2_hash = h2(hash); + let mut probe_seq = self.probe_seq(hash); + + loop { + // SAFETY: + // * Caller of this function ensures that the control bytes are properly initialized. + // + // * `ProbeSeq.pos` cannot be greater than `self.bucket_mask = self.buckets() - 1` + // of the table due to masking with `self.bucket_mask`. + // + // * Even if `ProbeSeq.pos` returns `position == self.bucket_mask`, it is safe to + // call `Group::load` due to the extended control bytes range, which is + // `self.bucket_mask + 1 + Group::WIDTH` (in fact, this means that the last control + // byte will never be read for the allocated table); + // + // * Also, even if `RawTableInner` is not already allocated, `ProbeSeq.pos` will + // always return "0" (zero), so Group::load will read unaligned `Group::static_empty()` + // bytes, which is safe (see RawTableInner::new_in). + let group = unsafe { Group::load(self.ctrl(probe_seq.pos)) }; + + for bit in group.match_byte(h2_hash) { + // This is the same as `(probe_seq.pos + bit) % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let index = (probe_seq.pos + bit) & self.bucket_mask; + + if likely(eq(index)) { + return Some(index); + } + } + + if likely(group.match_empty().any_bit_set()) { + return None; + } + + probe_seq.move_next(self.bucket_mask); + } + } + + /// Prepares for rehashing data in place (that is, without allocating new memory). + /// Converts all full index `control bytes` to `DELETED` and all `DELETED` control + /// bytes to `EMPTY`, i.e. performs the following conversion: + /// + /// - `EMPTY` control bytes -> `EMPTY`; + /// - `DELETED` control bytes -> `EMPTY`; + /// - `FULL` control bytes -> `DELETED`. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The caller of this function must convert the `DELETED` bytes back to `FULL` + /// bytes when re-inserting them into their ideal position (which was impossible + /// to do during the first insert due to tombstones). If the caller does not do + /// this, then calling this function may result in a memory leak. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes otherwise + /// calling this function results in [`undefined behavior`]. + /// + /// Calling this function on a table that has not been allocated results in + /// [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::mut_mut)] + #[inline] + unsafe fn prepare_rehash_in_place(&mut self) { + // Bulk convert all full control bytes to DELETED, and all DELETED control bytes to EMPTY. + // This effectively frees up all buckets containing a DELETED entry. + // + // SAFETY: + // 1. `i` is guaranteed to be within bounds since we are iterating from zero to `buckets - 1`; + // 2. Even if `i` will be `i == self.bucket_mask`, it is safe to call `Group::load_aligned` + // due to the extended control bytes range, which is `self.bucket_mask + 1 + Group::WIDTH`; + // 3. The caller of this function guarantees that [`RawTableInner`] has already been allocated; + // 4. We can use `Group::load_aligned` and `Group::store_aligned` here since we start from 0 + // and go to the end with a step equal to `Group::WIDTH` (see TableLayout::calculate_layout_for). + for i in (0..self.buckets()).step_by(Group::WIDTH) { + let group = Group::load_aligned(self.ctrl(i)); + let group = group.convert_special_to_empty_and_full_to_deleted(); + group.store_aligned(self.ctrl(i)); + } + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + // + // SAFETY: The caller of this function guarantees that [`RawTableInner`] + // has already been allocated + if unlikely(self.buckets() < Group::WIDTH) { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe + self.ctrl(0) + .copy_to(self.ctrl(Group::WIDTH), self.buckets()); + } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.buckets() == self.bucket_mask + 1` is safe + self.ctrl(0) + .copy_to(self.ctrl(self.buckets()), Group::WIDTH); + } + } + + /// Returns an iterator over every element in the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result + /// is [`undefined behavior`]: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `RawIter`. Because we cannot make the `next` method unsafe on + /// the `RawIter` struct, we have to make the `iter` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise using the returned [`RawIter`] results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn iter(&self) -> RawIter { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.data_end()` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. `data` bucket index in the table is equal to the `ctrl` index (i.e. + // equal to zero). + // 3. We pass the exact value of buckets of the table to the function. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + // CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + // with loading `Group` bytes from the heap works properly, even if the result + // of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + // `RawTableInner::set_ctrl` function. + // + // P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let data = Bucket::from_base_index(self.data_end(), 0); + RawIter { + // SAFETY: See explanation above + iter: RawIterRange::new(self.ctrl.as_ptr(), data, self.buckets()), + items: self.items, + } + } + + /// Executes the destructors (if any) of the values stored in the table. + /// + /// # Note + /// + /// This function does not erase the control bytes of the table and does + /// not make any changes to the `items` or `growth_left` fields of the + /// table. If necessary, the caller of this function must manually set + /// up these table fields, for example using the [`clear_no_drop`] function. + /// + /// Be careful during calling this function, because drop function of + /// the elements can panic, and this can leave table in an inconsistent + /// state. + /// + /// # Safety + /// + /// The type `T` must be the actual type of the elements stored in the table, + /// otherwise calling this function may result in [`undefined behavior`]. + /// + /// If `T` is a type that should be dropped and **the table is not empty**, + /// calling this function more than once results in [`undefined behavior`]. + /// + /// If `T` is not [`Copy`], attempting to use values stored in the table after + /// calling this function may result in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`Bucket::drop`] / [`Bucket::as_ptr`] methods, for more information + /// about of properly removing or saving `element` from / into the [`RawTable`] / + /// [`RawTableInner`]. + /// + /// [`Bucket::drop`]: Bucket::drop + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`clear_no_drop`]: RawTableInner::clear_no_drop + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_elements(&mut self) { + // Check that `self.items != 0`. Protects against the possibility + // of creating an iterator on an table with uninitialized control bytes. + if T::NEEDS_DROP && self.items != 0 { + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `RawIter` iterator, and the caller of this function + // must uphold the safety contract for `drop_elements` method. + for item in self.iter::() { + // SAFETY: The caller must uphold the safety contract for + // `drop_elements` method. + item.drop(); + } + } + } + + /// Executes the destructors (if any) of the values stored in the table and than + /// deallocates the table. + /// + /// # Note + /// + /// Calling this function automatically makes invalid (dangling) all instances of + /// buckets ([`Bucket`]) and makes invalid (dangling) the `ctrl` field of the table. + /// + /// This function does not make any changes to the `bucket_mask`, `items` or `growth_left` + /// fields of the table. If necessary, the caller of this function must manually set + /// up these table fields. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * Calling this function more than once; + /// + /// * The type `T` must be the actual type of the elements stored in the table. + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that + /// was used to allocate this table. + /// + /// The caller of this function should pay attention to the possibility of the + /// elements' drop function panicking, because this: + /// + /// * May leave the table in an inconsistent state; + /// + /// * Memory is never deallocated, so a memory leak may occur. + /// + /// Attempt to use the `ctrl` field of the table (dereference) after calling this + /// function results in [`undefined behavior`]. + /// + /// It is safe to call this function on a table that has not been allocated, + /// on a table with uninitialized control bytes, and on a table with no actual + /// data but with `Full` control bytes if `self.items == 0`. + /// + /// See also [`RawTableInner::drop_elements`] or [`RawTableInner::free_buckets`] + /// for more information. + /// + /// [`RawTableInner::drop_elements`]: RawTableInner::drop_elements + /// [`RawTableInner::free_buckets`]: RawTableInner::free_buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + unsafe fn drop_inner_table(&mut self, alloc: &A, table_layout: TableLayout) { + if !self.is_empty_singleton() { + unsafe { + // SAFETY: The caller must uphold the safety contract for `drop_inner_table` method. + self.drop_elements::(); + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller must uphold the safety contract for `drop_inner_table` method. + self.free_buckets(alloc, table_layout); + } + } + } + + /// Returns a pointer to an element in the table (convenience for + /// `Bucket::from_base_index(self.data_end::(), index)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`Bucket`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If `mem::size_of::() != 0`, then the safety rules are directly derived from the + /// safety rules of the [`Bucket::from_base_index`] function. Therefore, when calling + /// this function, the following safety rules must be observed: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`. + /// + /// * The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`Bucket`] may result in [`undefined behavior`]. + /// + /// It is safe to call this function with index of zero (`index == 0`) on a table that has + /// not been allocated, but using the returned [`Bucket`] results in [`undefined behavior`]. + /// + /// If `mem::size_of::() == 0`, then the only requirement is that the `index` must + /// not be greater than the number returned by the [`RawTable::buckets`] function, i.e. + /// `(index + 1) <= self.buckets()`. + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::buckets() - 1"): + /// + /// `table.bucket(3).as_ptr()` returns a pointer that points here in the `data` + /// part of the `RawTableInner`, i.e. to the start of T3 (see [`Bucket::as_ptr`]) + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// ^ \__________ __________/ + /// `table.bucket(3)` returns a pointer that points \/ + /// here in the `data` part of the `RawTableInner` additional control bytes + /// (to the end of T3) `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`Bucket::from_base_index`]: Bucket::from_base_index + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn bucket(&self, index: usize) -> Bucket { + debug_assert_ne!(self.bucket_mask, 0); + debug_assert!(index < self.buckets()); + Bucket::from_base_index(self.data_end(), index) + } + + /// Returns a raw `*mut u8` pointer to the start of the `data` element in the table + /// (convenience for `self.data_end::().as_ptr().sub((index + 1) * size_of)`). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned `*mut u8`, + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The table must already be allocated; + /// + /// * The `index` must not be greater than the number returned by the [`RawTableInner::buckets`] + /// function, i.e. `(index + 1) <= self.buckets()`; + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// ```none + /// If mem::size_of::() != 0 then return a pointer to the `element` in the `data part` of the table + /// (we start counting from "0", so that in the expression T[n], the "n" index actually one less than + /// the "buckets" number of our `RawTableInner`, i.e. "n = RawTableInner::buckets() - 1"): + /// + /// `table.bucket_ptr(3, mem::size_of::())` returns a pointer that points here in the + /// `data` part of the `RawTableInner`, i.e. to the start of T3 + /// | + /// | `base = table.data_end::()` points here + /// | (to the start of CT0 or to the end of T0) + /// v v + /// [Pad], T_n, ..., |T3|, T2, T1, T0, |CT0, CT1, CT2, CT3, ..., CT_n, CTa_0, CTa_1, ..., CTa_m + /// \__________ __________/ + /// \/ + /// additional control bytes + /// `m = Group::WIDTH - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`; + /// CTa_0...CTa_m - additional control bytes (so that the search with loading `Group` bytes from + /// the heap works properly, even if the result of `h1(hash) & self.bucket_mask` + /// is equal to `self.bucket_mask`). See also `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn bucket_ptr(&self, index: usize, size_of: usize) -> *mut u8 { + debug_assert_ne!(self.bucket_mask, 0); + debug_assert!(index < self.buckets()); + let base: *mut u8 = self.data_end().as_ptr(); + base.sub((index + 1) * size_of) + } + + /// Returns pointer to one past last `data` element in the table as viewed from + /// the start point of the allocation (convenience for `self.ctrl.cast()`). + /// + /// This function actually returns a pointer to the end of the `data element` at + /// index "0" (zero). + /// + /// The caller must ensure that the `RawTableInner` outlives the returned [`NonNull`], + /// otherwise using it may result in [`undefined behavior`]. + /// + /// # Note + /// + /// The type `T` must be the actual type of the elements stored in the table, otherwise + /// using the returned [`NonNull`] may result in [`undefined behavior`]. + /// + /// ```none + /// `table.data_end::()` returns pointer that points here + /// (to the end of `T0`) + /// ∨ + /// [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, CTa_0, CTa_1, ..., CTa_m + /// \________ ________/ + /// \/ + /// `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + /// + /// where: T0...T_n - our stored data; + /// CT0...CT_n - control bytes or metadata for `data`. + /// CTa_0...CTa_m - additional control bytes, where `m = Group::WIDTH - 1` (so that the search + /// with loading `Group` bytes from the heap works properly, even if the result + /// of `h1(hash) & self.bucket_mask` is equal to `self.bucket_mask`). See also + /// `RawTableInner::set_ctrl` function. + /// + /// P.S. `h1(hash) & self.bucket_mask` is the same as `hash as usize % self.buckets()` because the number + /// of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + /// ``` + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + fn data_end(&self) -> NonNull { + self.ctrl.cast() + } + + /// Returns an iterator-like object for a probe sequence on the table. + /// + /// This iterator never terminates, but is guaranteed to visit each bucket + /// group exactly once. The loop using `probe_seq` must terminate upon + /// reaching a group containing an empty bucket. + #[inline] + fn probe_seq(&self, hash: u64) -> ProbeSeq { + ProbeSeq { + // This is the same as `hash as usize % self.buckets()` because the number + // of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + pos: h1(hash) & self.bucket_mask, + stride: 0, + } + } + + /// Returns the index of a bucket for which a value must be inserted if there is enough rooom + /// in the table, otherwise returns error + #[cfg(feature = "raw")] + #[inline] + unsafe fn prepare_insert_no_grow(&mut self, hash: u64) -> Result { + let index = self.find_insert_slot(hash).index; + let old_ctrl = *self.ctrl(index); + if unlikely(self.growth_left == 0 && special_is_empty(old_ctrl)) { + Err(()) + } else { + self.record_item_insert_at(index, old_ctrl, hash); + Ok(index) + } + } + + #[inline] + unsafe fn record_item_insert_at(&mut self, index: usize, old_ctrl: u8, hash: u64) { + self.growth_left -= usize::from(special_is_empty(old_ctrl)); + self.set_ctrl_h2(index, hash); + self.items += 1; + } + + #[inline] + fn is_in_same_group(&self, i: usize, new_i: usize, hash: u64) -> bool { + let probe_seq_pos = self.probe_seq(hash).pos; + let probe_index = + |pos: usize| (pos.wrapping_sub(probe_seq_pos) & self.bucket_mask) / Group::WIDTH; + probe_index(i) == probe_index(new_i) + } + + /// Sets a control byte to the hash, and possibly also the replicated control byte at + /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl`] + /// method. Thus, in order to uphold the safety contracts for the method, you must observe the + /// following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::set_ctrl`]: RawTableInner::set_ctrl + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn set_ctrl_h2(&mut self, index: usize, hash: u64) { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl_h2`] + self.set_ctrl(index, h2(hash)); + } + + /// Replaces the hash in the control byte at the given index with the provided one, + /// and possibly also replicates the new control byte at the end of the array of control + /// bytes, returning the old control byte. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// The safety rules are directly derived from the safety rules for [`RawTableInner::set_ctrl_h2`] + /// and [`RawTableInner::ctrl`] methods. Thus, in order to uphold the safety contracts for both + /// methods, you must observe the following rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::set_ctrl_h2`]: RawTableInner::set_ctrl_h2 + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn replace_ctrl_h2(&mut self, index: usize, hash: u64) -> u8 { + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::replace_ctrl_h2`] + let prev_ctrl = *self.ctrl(index); + self.set_ctrl_h2(index, hash); + prev_ctrl + } + + /// Sets a control byte, and possibly also the replicated control byte at + /// the end of the array. + /// + /// This function does not make any changes to the `data` parts of the table, + /// or any changes to the `items` or `growth_left` field of the table. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn set_ctrl(&mut self, index: usize, ctrl: u8) { + // Replicate the first Group::WIDTH control bytes at the end of + // the array without using a branch. If the tables smaller than + // the group width (self.buckets() < Group::WIDTH), + // `index2 = Group::WIDTH + index`, otherwise `index2` is: + // + // - If index >= Group::WIDTH then index == index2. + // - Otherwise index2 == self.bucket_mask + 1 + index. + // + // The very last replicated control byte is never actually read because + // we mask the initial index for unaligned loads, but we write it + // anyways because it makes the set_ctrl implementation simpler. + // + // If there are fewer buckets than Group::WIDTH then this code will + // replicate the buckets at the end of the trailing group. For example + // with 2 buckets and a group size of 4, the control bytes will look + // like this: + // + // Real | Replicated + // --------------------------------------------- + // | [A] | [B] | [EMPTY] | [EMPTY] | [A] | [B] | + // --------------------------------------------- + + // This is the same as `(index.wrapping_sub(Group::WIDTH)) % self.buckets() + Group::WIDTH` + // because the number of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let index2 = ((index.wrapping_sub(Group::WIDTH)) & self.bucket_mask) + Group::WIDTH; + + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::set_ctrl`] + *self.ctrl(index) = ctrl; + *self.ctrl(index2) = ctrl; + } + + /// Returns a pointer to a control byte. + /// + /// # Safety + /// + /// For the allocated [`RawTableInner`], the result is [`Undefined Behavior`], + /// if the `index` is greater than the `self.bucket_mask + 1 + Group::WIDTH`. + /// In that case, calling this function with `index == self.bucket_mask + 1 + Group::WIDTH` + /// will return a pointer to the end of the allocated table and it is useless on its own. + /// + /// Calling this function with `index >= self.bucket_mask + 1 + Group::WIDTH` on a + /// table that has not been allocated results in [`Undefined Behavior`]. + /// + /// So to satisfy both requirements you should always follow the rule that + /// `index < self.bucket_mask + 1 + Group::WIDTH` + /// + /// Calling this function on [`RawTableInner`] that are not already allocated is safe + /// for read-only purpose. + /// + /// See also [`Bucket::as_ptr()`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`Bucket::as_ptr()`]: Bucket::as_ptr() + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn ctrl(&self, index: usize) -> *mut u8 { + debug_assert!(index < self.num_ctrl_bytes()); + // SAFETY: The caller must uphold the safety rules for the [`RawTableInner::ctrl`] + self.ctrl.as_ptr().add(index) + } + + #[inline] + fn buckets(&self) -> usize { + self.bucket_mask + 1 + } + + /// Checks whether the bucket at `index` is full. + /// + /// # Safety + /// + /// The caller must ensure `index` is less than the number of buckets. + #[inline] + unsafe fn is_bucket_full(&self, index: usize) -> bool { + debug_assert!(index < self.buckets()); + is_full(*self.ctrl(index)) + } + + #[inline] + fn num_ctrl_bytes(&self) -> usize { + self.bucket_mask + 1 + Group::WIDTH + } + + #[inline] + fn is_empty_singleton(&self) -> bool { + self.bucket_mask == 0 + } + + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating, + /// and return it inside ScopeGuard to protect against panic in the hash + /// function. + /// + /// # Note + /// + /// It is recommended (but not required): + /// + /// * That the new table's `capacity` be greater than or equal to `self.items`. + /// + /// * The `alloc` is the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `table_layout` is the same [`TableLayout`] as the `TableLayout` used + /// to allocate this table. + /// + /// If `table_layout` does not match the `TableLayout` that was used to allocate + /// this table, then using `mem::swap` with the `self` and the new table returned + /// by this function results in [`undefined behavior`]. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::mut_mut)] + #[inline] + fn prepare_resize<'a, A>( + &self, + alloc: &'a A, + table_layout: TableLayout, + capacity: usize, + fallibility: Fallibility, + ) -> Result, TryReserveError> + where + A: Allocator, + { + debug_assert!(self.items <= capacity); + + // Allocate and initialize the new table. + let new_table = + RawTableInner::fallible_with_capacity(alloc, table_layout, capacity, fallibility)?; + + // The hash function may panic, in which case we simply free the new + // table without dropping any elements that may have been copied into + // it. + // + // This guard is also used to free the old table on success, see + // the comment at the bottom of this function. + Ok(guard(new_table, move |self_| { + if !self_.is_empty_singleton() { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that the `alloc` and `table_layout` matches the + // [`Allocator`] and [`TableLayout`] used to allocate this table. + unsafe { self_.free_buckets(alloc, table_layout) }; + } + })) + } + + /// Reserves or rehashes to make room for `additional` more elements. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table. + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table. + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::inline_always)] + #[inline(always)] + unsafe fn reserve_rehash_inner( + &mut self, + alloc: &A, + additional: usize, + hasher: &dyn Fn(&mut Self, usize) -> u64, + fallibility: Fallibility, + layout: TableLayout, + drop: Option, + ) -> Result<(), TryReserveError> + where + A: Allocator, + { + // Avoid `Option::ok_or_else` because it bloats LLVM IR. + let new_items = match self.items.checked_add(additional) { + Some(new_items) => new_items, + None => return Err(fallibility.capacity_overflow()), + }; + let full_capacity = bucket_mask_to_capacity(self.bucket_mask); + if new_items <= full_capacity / 2 { + // Rehash in-place without re-allocating if we have plenty of spare + // capacity that is locked up due to DELETED entries. + + // SAFETY: + // 1. We know for sure that `[`RawTableInner`]` has already been allocated + // (since new_items <= full_capacity / 2); + // 2. The caller ensures that `drop` function is the actual drop function of + // the elements stored in the table. + // 3. The caller ensures that `layout` matches the [`TableLayout`] that was + // used to allocate this table. + // 4. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.rehash_in_place(hasher, layout.size, drop); + Ok(()) + } else { + // Otherwise, conservatively resize to at least the next size up + // to avoid churning deletes into frequent rehashes. + // + // SAFETY: + // 1. We know for sure that `capacity >= self.items`. + // 2. The caller ensures that `alloc` and `layout` matches the [`Allocator`] and + // [`TableLayout`] that were used to allocate this table. + // 3. The caller ensures that the control bytes of the `RawTableInner` + // are already initialized. + self.resize_inner( + alloc, + usize::max(new_items, full_capacity + 1), + hasher, + fallibility, + layout, + ) + } + } + + /// Returns an iterator over full buckets indices in the table. + /// + /// # Safety + /// + /// Behavior is undefined if any of the following conditions are violated: + /// + /// * The caller has to ensure that the `RawTableInner` outlives the + /// `FullBucketsIndices`. Because we cannot make the `next` method + /// unsafe on the `FullBucketsIndices` struct, we have to make the + /// `full_buckets_indices` method unsafe. + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + #[inline(always)] + unsafe fn full_buckets_indices(&self) -> FullBucketsIndices { + // SAFETY: + // 1. Since the caller of this function ensures that the control bytes + // are properly initialized and `self.ctrl(0)` points to the start + // of the array of control bytes, therefore: `ctrl` is valid for reads, + // properly aligned to `Group::WIDTH` and points to the properly initialized + // control bytes. + // 2. The value of `items` is equal to the amount of data (values) added + // to the table. + // + // `ctrl` points here (to the start + // of the first control byte `CT0`) + // ∨ + // [Pad], T_n, ..., T1, T0, |CT0, CT1, ..., CT_n|, Group::WIDTH + // \________ ________/ + // \/ + // `n = buckets - 1`, i.e. `RawTableInner::buckets() - 1` + // + // where: T0...T_n - our stored data; + // CT0...CT_n - control bytes or metadata for `data`. + let ctrl = NonNull::new_unchecked(self.ctrl(0)); + + FullBucketsIndices { + // Load the first group + // SAFETY: See explanation above. + current_group: Group::load_aligned(ctrl.as_ptr()).match_full().into_iter(), + group_first_index: 0, + ctrl, + items: self.items, + } + } + + /// Allocates a new table of a different size and moves the contents of the + /// current table into it. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` used + /// to allocate this table; + /// + /// * The `layout` must be the same [`TableLayout`] as the `TableLayout` + /// used to allocate this table; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// The caller of this function must ensure that `capacity >= self.items` + /// otherwise: + /// + /// * If `self.items != 0`, calling of this function with `capacity == 0` + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) < Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// results in [`undefined behavior`]. + /// + /// * If `capacity_to_buckets(capacity) >= Group::WIDTH` and + /// `self.items > capacity_to_buckets(capacity)` calling this function + /// are never return (will go into an infinite loop). + /// + /// Note: It is recommended (but not required) that the new table's `capacity` + /// be greater than or equal to `self.items`. In case if `capacity <= self.items` + /// this function can never return. See [`RawTableInner::find_insert_slot`] for + /// more information. + /// + /// [`RawTableInner::find_insert_slot`]: RawTableInner::find_insert_slot + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::inline_always)] + #[inline(always)] + unsafe fn resize_inner( + &mut self, + alloc: &A, + capacity: usize, + hasher: &dyn Fn(&mut Self, usize) -> u64, + fallibility: Fallibility, + layout: TableLayout, + ) -> Result<(), TryReserveError> + where + A: Allocator, + { + // SAFETY: We know for sure that `alloc` and `layout` matches the [`Allocator`] and [`TableLayout`] + // that were used to allocate this table. + let mut new_table = self.prepare_resize(alloc, layout, capacity, fallibility)?; + + // SAFETY: We know for sure that RawTableInner will outlive the + // returned `FullBucketsIndices` iterator, and the caller of this + // function ensures that the control bytes are properly initialized. + for full_byte_index in self.full_buckets_indices() { + // This may panic. + let hash = hasher(self, full_byte_index); + + // SAFETY: + // We can use a simpler version of insert() here since: + // 1. There are no DELETED entries. + // 2. We know there is enough space in the table. + // 3. All elements are unique. + // 4. The caller of this function guarantees that `capacity > 0` + // so `new_table` must already have some allocated memory. + // 5. We set `growth_left` and `items` fields of the new table + // after the loop. + // 6. We insert into the table, at the returned index, the data + // matching the given hash immediately after calling this function. + let (new_index, _) = new_table.prepare_insert_slot(hash); + + // SAFETY: + // + // * `src` is valid for reads of `layout.size` bytes, since the + // table is alive and the `full_byte_index` is guaranteed to be + // within bounds (see `FullBucketsIndices::next_impl`); + // + // * `dst` is valid for writes of `layout.size` bytes, since the + // caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate old table and we have the `new_index` + // returned by `prepare_insert_slot`. + // + // * Both `src` and `dst` are properly aligned. + // + // * Both `src` and `dst` point to different region of memory. + ptr::copy_nonoverlapping( + self.bucket_ptr(full_byte_index, layout.size), + new_table.bucket_ptr(new_index, layout.size), + layout.size, + ); + } + + // The hash function didn't panic, so we can safely set the + // `growth_left` and `items` fields of the new table. + new_table.growth_left -= self.items; + new_table.items = self.items; + + // We successfully copied all elements without panicking. Now replace + // self with the new table. The old table will have its memory freed but + // the items will not be dropped (since they have been moved into the + // new table). + // SAFETY: The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. + mem::swap(self, &mut new_table); + + Ok(()) + } + + /// Rehashes the contents of the table in place (i.e. without changing the + /// allocation). + /// + /// If `hasher` panics then some the table's contents may be lost. + /// + /// This uses dynamic dispatch to reduce the amount of + /// code generated, but it is eliminated by LLVM optimizations when inlined. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`undefined behavior`]: + /// + /// * The `size_of` must be equal to the size of the elements stored in the table; + /// + /// * The `drop` function (`fn(*mut u8)`) must be the actual drop function of + /// the elements stored in the table. + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The [`RawTableInner`] must have properly initialized control bytes. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::inline_always)] + #[cfg_attr(feature = "inline-more", inline(always))] + #[cfg_attr(not(feature = "inline-more"), inline)] + unsafe fn rehash_in_place( + &mut self, + hasher: &dyn Fn(&mut Self, usize) -> u64, + size_of: usize, + drop: Option, + ) { + // If the hash function panics then properly clean up any elements + // that we haven't rehashed yet. We unfortunately can't preserve the + // element since we lost their hash and have no way of recovering it + // without risking another panic. + self.prepare_rehash_in_place(); + + let mut guard = guard(self, move |self_| { + if let Some(drop) = drop { + for i in 0..self_.buckets() { + if *self_.ctrl(i) == DELETED { + self_.set_ctrl(i, EMPTY); + drop(self_.bucket_ptr(i, size_of)); + self_.items -= 1; + } + } + } + self_.growth_left = bucket_mask_to_capacity(self_.bucket_mask) - self_.items; + }); + + // At this point, DELETED elements are elements that we haven't + // rehashed yet. Find them and re-insert them at their ideal + // position. + 'outer: for i in 0..guard.buckets() { + if *guard.ctrl(i) != DELETED { + continue; + } + + let i_p = guard.bucket_ptr(i, size_of); + + 'inner: loop { + // Hash the current item + let hash = hasher(*guard, i); + + // Search for a suitable place to put it + // + // SAFETY: Caller of this function ensures that the control bytes + // are properly initialized. + let new_i = guard.find_insert_slot(hash).index; + + // Probing works by scanning through all of the control + // bytes in groups, which may not be aligned to the group + // size. If both the new and old position fall within the + // same unaligned group, then there is no benefit in moving + // it and we can just continue to the next item. + if likely(guard.is_in_same_group(i, new_i, hash)) { + guard.set_ctrl_h2(i, hash); + continue 'outer; + } + + let new_i_p = guard.bucket_ptr(new_i, size_of); + + // We are moving the current item to a new position. Write + // our H2 to the control byte of the new position. + let prev_ctrl = guard.replace_ctrl_h2(new_i, hash); + if prev_ctrl == EMPTY { + guard.set_ctrl(i, EMPTY); + // If the target slot is empty, simply move the current + // element into the new slot and clear the old control + // byte. + ptr::copy_nonoverlapping(i_p, new_i_p, size_of); + continue 'outer; + } else { + // If the target slot is occupied, swap the two elements + // and then continue processing the element that we just + // swapped into the old slot. + debug_assert_eq!(prev_ctrl, DELETED); + ptr::swap_nonoverlapping(i_p, new_i_p, size_of); + continue 'inner; + } + } + } + + guard.growth_left = bucket_mask_to_capacity(guard.bucket_mask) - guard.items; + + mem::forget(guard); + } + + /// Deallocates the table without dropping any entries. + /// + /// # Note + /// + /// This function must be called only after [`drop_elements`](RawTableInner::drop_elements), + /// else it can lead to leaking of memory. Also calling this function automatically + /// makes invalid (dangling) all instances of buckets ([`Bucket`]) and makes invalid + /// (dangling) the `ctrl` field of the table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * The `alloc` must be the same [`Allocator`] as the `Allocator` that was used + /// to allocate this table. + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` that was used + /// to allocate this table. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[inline] + unsafe fn free_buckets(&mut self, alloc: &A, table_layout: TableLayout) + where + A: Allocator, + { + // SAFETY: The caller must uphold the safety contract for `free_buckets` + // method. + let (ptr, layout) = self.allocation_info(table_layout); + alloc.deallocate(ptr, layout); + } + + /// Returns a pointer to the allocated memory and the layout that was used to + /// allocate the table. + /// + /// # Safety + /// + /// Caller of this function must observe the following safety rules: + /// + /// * The [`RawTableInner`] has already been allocated, otherwise + /// calling this function results in [`undefined behavior`] + /// + /// * The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[inline] + unsafe fn allocation_info(&self, table_layout: TableLayout) -> (NonNull, Layout) { + debug_assert!( + !self.is_empty_singleton(), + "this function can only be called on non-empty tables" + ); + + // Avoid `Option::unwrap_or_else` because it bloats LLVM IR. + let (layout, ctrl_offset) = match table_layout.calculate_layout_for(self.buckets()) { + Some(lco) => lco, + None => unsafe { hint::unreachable_unchecked() }, + }; + ( + // SAFETY: The caller must uphold the safety contract for `allocation_info` method. + unsafe { NonNull::new_unchecked(self.ctrl.as_ptr().sub(ctrl_offset)) }, + layout, + ) + } + + /// Returns a pointer to the allocated memory and the layout that was used to + /// allocate the table. If [`RawTableInner`] has not been allocated, this + /// function return `dangling` pointer and `()` (unit) layout. + /// + /// # Safety + /// + /// The `table_layout` must be the same [`TableLayout`] as the `TableLayout` + /// that was used to allocate this table. Failure to comply with this condition + /// may result in [`undefined behavior`]. + /// + /// See also [`GlobalAlloc::dealloc`] or [`Allocator::deallocate`] for more information. + /// + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [`GlobalAlloc::dealloc`]: https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html#tymethod.dealloc + /// [`Allocator::deallocate`]: https://doc.rust-lang.org/alloc/alloc/trait.Allocator.html#tymethod.deallocate + #[cfg(feature = "raw")] + unsafe fn allocation_info_or_zero(&self, table_layout: TableLayout) -> (NonNull, Layout) { + if self.is_empty_singleton() { + (NonNull::dangling(), Layout::new::<()>()) + } else { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. The caller ensures that `table_layout` matches the [`TableLayout`] + // that was used to allocate this table. + unsafe { self.allocation_info(table_layout) } + } + } + + /// Marks all table buckets as empty without dropping their contents. + #[inline] + fn clear_no_drop(&mut self) { + if !self.is_empty_singleton() { + unsafe { + self.ctrl(0).write_bytes(EMPTY, self.num_ctrl_bytes()); + } + } + self.items = 0; + self.growth_left = bucket_mask_to_capacity(self.bucket_mask); + } + + /// Erases the [`Bucket`]'s control byte at the given index so that it does not + /// triggered as full, decreases the `items` of the table and, if it can be done, + /// increases `self.growth_left`. + /// + /// This function does not actually erase / drop the [`Bucket`] itself, i.e. it + /// does not make any changes to the `data` parts of the table. The caller of this + /// function must take care to properly drop the `data`, otherwise calling this + /// function may result in a memory leak. + /// + /// # Safety + /// + /// You must observe the following safety rules when calling this function: + /// + /// * The [`RawTableInner`] has already been allocated; + /// + /// * It must be the full control byte at the given position; + /// + /// * The `index` must not be greater than the `RawTableInner.bucket_mask`, i.e. + /// `index <= RawTableInner.bucket_mask` or, in other words, `(index + 1)` must + /// be no greater than the number returned by the function [`RawTableInner::buckets`]. + /// + /// Calling this function on a table that has not been allocated results in [`undefined behavior`]. + /// + /// Calling this function on a table with no elements is unspecified, but calling subsequent + /// functions is likely to result in [`undefined behavior`] due to overflow subtraction + /// (`self.items -= 1 cause overflow when self.items == 0`). + /// + /// See also [`Bucket::as_ptr`] method, for more information about of properly removing + /// or saving `data element` from / into the [`RawTable`] / [`RawTableInner`]. + /// + /// [`RawTableInner::buckets`]: RawTableInner::buckets + /// [`Bucket::as_ptr`]: Bucket::as_ptr + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline] + unsafe fn erase(&mut self, index: usize) { + debug_assert!(self.is_bucket_full(index)); + + // This is the same as `index.wrapping_sub(Group::WIDTH) % self.buckets()` because + // the number of buckets is a power of two, and `self.bucket_mask = self.buckets() - 1`. + let index_before = index.wrapping_sub(Group::WIDTH) & self.bucket_mask; + // SAFETY: + // - The caller must uphold the safety contract for `erase` method; + // - `index_before` is guaranteed to be in range due to masking with `self.bucket_mask` + let empty_before = Group::load(self.ctrl(index_before)).match_empty(); + let empty_after = Group::load(self.ctrl(index)).match_empty(); + + // Inserting and searching in the map is performed by two key functions: + // + // - The `find_insert_slot` function that looks up the index of any `EMPTY` or `DELETED` + // slot in a group to be able to insert. If it doesn't find an `EMPTY` or `DELETED` + // slot immediately in the first group, it jumps to the next `Group` looking for it, + // and so on until it has gone through all the groups in the control bytes. + // + // - The `find_inner` function that looks for the index of the desired element by looking + // at all the `FULL` bytes in the group. If it did not find the element right away, and + // there is no `EMPTY` byte in the group, then this means that the `find_insert_slot` + // function may have found a suitable slot in the next group. Therefore, `find_inner` + // jumps further, and if it does not find the desired element and again there is no `EMPTY` + // byte, then it jumps further, and so on. The search stops only if `find_inner` function + // finds the desired element or hits an `EMPTY` slot/byte. + // + // Accordingly, this leads to two consequences: + // + // - The map must have `EMPTY` slots (bytes); + // + // - You can't just mark the byte to be erased as `EMPTY`, because otherwise the `find_inner` + // function may stumble upon an `EMPTY` byte before finding the desired element and stop + // searching. + // + // Thus it is necessary to check all bytes after and before the erased element. If we are in + // a contiguous `Group` of `FULL` or `DELETED` bytes (the number of `FULL` or `DELETED` bytes + // before and after is greater than or equal to `Group::WIDTH`), then we must mark our byte as + // `DELETED` in order for the `find_inner` function to go further. On the other hand, if there + // is at least one `EMPTY` slot in the `Group`, then the `find_inner` function will still stumble + // upon an `EMPTY` byte, so we can safely mark our erased byte as `EMPTY` as well. + // + // Finally, since `index_before == (index.wrapping_sub(Group::WIDTH) & self.bucket_mask) == index` + // and given all of the above, tables smaller than the group width (self.buckets() < Group::WIDTH) + // cannot have `DELETED` bytes. + // + // Note that in this context `leading_zeros` refers to the bytes at the end of a group, while + // `trailing_zeros` refers to the bytes at the beginning of a group. + let ctrl = if empty_before.leading_zeros() + empty_after.trailing_zeros() >= Group::WIDTH { + DELETED + } else { + self.growth_left += 1; + EMPTY + }; + // SAFETY: the caller must uphold the safety contract for `erase` method. + self.set_ctrl(index, ctrl); + self.items -= 1; + } +} + +impl Clone for RawTable { + fn clone(&self) -> Self { + if self.table.is_empty_singleton() { + Self::new_in(self.alloc.clone()) + } else { + unsafe { + // Avoid `Result::ok_or_else` because it bloats LLVM IR. + // + // SAFETY: This is safe as we are taking the size of an already allocated table + // and therefore сapacity overflow cannot occur, `self.table.buckets()` is power + // of two and all allocator errors will be caught inside `RawTableInner::new_uninitialized`. + let mut new_table = match Self::new_uninitialized( + self.alloc.clone(), + self.table.buckets(), + Fallibility::Infallible, + ) { + Ok(table) => table, + Err(_) => hint::unreachable_unchecked(), + }; + + // Cloning elements may fail (the clone function may panic). But we don't + // need to worry about uninitialized control bits, since: + // 1. The number of items (elements) in the table is zero, which means that + // the control bits will not be readed by Drop function. + // 2. The `clone_from_spec` method will first copy all control bits from + // `self` (thus initializing them). But this will not affect the `Drop` + // function, since the `clone_from_spec` function sets `items` only after + // successfully clonning all elements. + new_table.clone_from_spec(self); + new_table + } + } + } + + fn clone_from(&mut self, source: &Self) { + if source.table.is_empty_singleton() { + let mut old_inner = mem::replace(&mut self.table, RawTableInner::NEW); + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If any elements' drop function panics, then there will only be a memory leak, + // because we have replaced the inner table with a new one. + old_inner.drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } else { + unsafe { + // Make sure that if any panics occurs, we clear the table and + // leave it in an empty state. + let mut self_ = guard(self, |self_| { + self_.clear_no_drop(); + }); + + // First, drop all our elements without clearing the control + // bytes. If this panics then the scope guard will clear the + // table, leaking any elements that were not dropped yet. + // + // This leak is unavoidable: we can't try dropping more elements + // since this could lead to another panic and abort the process. + // + // SAFETY: If something gets wrong we clear our table right after + // dropping the elements, so there is no double drop, since `items` + // will be equal to zero. + self_.table.drop_elements::(); + + // If necessary, resize our table to match the source. + if self_.buckets() != source.buckets() { + let new_inner = match RawTableInner::new_uninitialized( + &self_.alloc, + Self::TABLE_LAYOUT, + source.buckets(), + Fallibility::Infallible, + ) { + Ok(table) => table, + Err(_) => hint::unreachable_unchecked(), + }; + // Replace the old inner with new uninitialized one. It's ok, since if something gets + // wrong `ScopeGuard` will initialize all control bytes and leave empty table. + let mut old_inner = mem::replace(&mut self_.table, new_inner); + if !old_inner.is_empty_singleton() { + // SAFETY: + // 1. We have checked that our table is allocated. + // 2. We know for sure that `alloc` and `table_layout` matches + // the [`Allocator`] and [`TableLayout`] that were used to allocate this table. + old_inner.free_buckets(&self_.alloc, Self::TABLE_LAYOUT); + } + } + + // Cloning elements may fail (the clone function may panic), but the `ScopeGuard` + // inside the `clone_from_impl` function will take care of that, dropping all + // cloned elements if necessary. Our `ScopeGuard` will clear the table. + self_.clone_from_spec(source); + + // Disarm the scope guard if cloning was successful. + ScopeGuard::into_inner(self_); + } + } + } +} + +/// Specialization of `clone_from` for `Copy` types +trait RawTableClone { + unsafe fn clone_from_spec(&mut self, source: &Self); +} +impl RawTableClone for RawTable { + default_fn! { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_spec(&mut self, source: &Self) { + self.clone_from_impl(source); + } + } +} +#[cfg(feature = "nightly")] +impl RawTableClone for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_spec(&mut self, source: &Self) { + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + source + .data_start() + .as_ptr() + .copy_to_nonoverlapping(self.data_start().as_ptr(), self.table.buckets()); + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } +} + +impl RawTable { + /// Common code for clone and clone_from. Assumes: + /// - `self.buckets() == source.buckets()`. + /// - Any existing elements have been dropped. + /// - The control bytes are not initialized yet. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn clone_from_impl(&mut self, source: &Self) { + // Copy the control bytes unchanged. We do this in a single pass + source + .table + .ctrl(0) + .copy_to_nonoverlapping(self.table.ctrl(0), self.table.num_ctrl_bytes()); + + // The cloning of elements may panic, in which case we need + // to make sure we drop only the elements that have been + // cloned so far. + let mut guard = guard((0, &mut *self), |(index, self_)| { + if T::NEEDS_DROP { + for i in 0..*index { + if self_.is_bucket_full(i) { + self_.bucket(i).drop(); + } + } + } + }); + + for from in source.iter() { + let index = source.bucket_index(&from); + let to = guard.1.bucket(index); + to.write(from.as_ref().clone()); + + // Update the index in case we need to unwind. + guard.0 = index + 1; + } + + // Successfully cloned all items, no need to clean up. + mem::forget(guard); + + self.table.items = source.table.items; + self.table.growth_left = source.table.growth_left; + } + + /// Variant of `clone_from` to use when a hasher is available. + #[cfg(feature = "raw")] + pub fn clone_from_with_hasher(&mut self, source: &Self, hasher: impl Fn(&T) -> u64) { + // If we have enough capacity in the table, just clear it and insert + // elements one by one. We don't do this if we have the same number of + // buckets as the source since we can just copy the contents directly + // in that case. + if self.table.buckets() != source.table.buckets() + && bucket_mask_to_capacity(self.table.bucket_mask) >= source.len() + { + self.clear(); + + let mut guard_self = guard(&mut *self, |self_| { + // Clear the partially copied table if a panic occurs, otherwise + // items and growth_left will be out of sync with the contents + // of the table. + self_.clear(); + }); + + unsafe { + for item in source.iter() { + // This may panic. + let item = item.as_ref().clone(); + let hash = hasher(&item); + + // We can use a simpler version of insert() here since: + // - there are no DELETED entries. + // - we know there is enough space in the table. + // - all elements are unique. + let (index, _) = guard_self.table.prepare_insert_slot(hash); + guard_self.bucket(index).write(item); + } + } + + // Successfully cloned all items, no need to clean up. + mem::forget(guard_self); + + self.table.items = source.table.items; + self.table.growth_left -= source.table.items; + } else { + self.clone_from(source); + } + } +} + +impl Default for RawTable { + #[inline] + fn default() -> Self { + Self::new_in(Default::default()) + } +} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawTable { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // SAFETY: + // 1. We call the function only once; + // 2. We know for sure that `alloc` and `table_layout` matches the [`Allocator`] + // and [`TableLayout`] that were used to allocate this table. + // 3. If the drop function of any elements fails, then only a memory leak will occur, + // and we don't care because we are inside the `Drop` function of the `RawTable`, + // so there won't be any table left in an inconsistent state. + self.table + .drop_inner_table::(&self.alloc, Self::TABLE_LAYOUT); + } + } +} + +impl IntoIterator for RawTable { + type Item = T; + type IntoIter = RawIntoIter; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> RawIntoIter { + unsafe { + let iter = self.iter(); + self.into_iter_from(iter) + } + } +} + +/// Iterator over a sub-range of a table. Unlike `RawIter` this iterator does +/// not track an item count. +pub(crate) struct RawIterRange { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMaskIter, + + // Pointer to the buckets for the current group. + data: Bucket, + + // Pointer to the next group of control bytes, + // Must be aligned to the group size. + next_ctrl: *const u8, + + // Pointer one past the last control byte of this range. + end: *const u8, +} + +impl RawIterRange { + /// Returns a `RawIterRange` covering a subset of a table. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`undefined behavior`]: + /// + /// * `ctrl` must be [valid] for reads, i.e. table outlives the `RawIterRange`; + /// + /// * `ctrl` must be properly aligned to the group size (Group::WIDTH); + /// + /// * `ctrl` must point to the array of properly initialized control bytes; + /// + /// * `data` must be the [`Bucket`] at the `ctrl` index in the table; + /// + /// * the value of `len` must be less than or equal to the number of table buckets, + /// and the returned value of `ctrl.as_ptr().add(len).offset_from(ctrl.as_ptr())` + /// must be positive. + /// + /// * The `ctrl.add(len)` pointer must be either in bounds or one + /// byte past the end of the same [allocated table]. + /// + /// * The `len` must be a power of two. + /// + /// [valid]: https://doc.rust-lang.org/std/ptr/index.html#safety + /// [`undefined behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn new(ctrl: *const u8, data: Bucket, len: usize) -> Self { + debug_assert_ne!(len, 0); + debug_assert_eq!(ctrl as usize % Group::WIDTH, 0); + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] + let end = ctrl.add(len); + + // Load the first group and advance ctrl to point to the next group + // SAFETY: The caller must uphold the safety rules for the [`RawIterRange::new`] + let current_group = Group::load_aligned(ctrl).match_full(); + let next_ctrl = ctrl.add(Group::WIDTH); + + Self { + current_group: current_group.into_iter(), + data, + next_ctrl, + end, + } + } + + /// Splits a `RawIterRange` into two halves. + /// + /// Returns `None` if the remaining range is smaller than or equal to the + /// group width. + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "rayon")] + pub(crate) fn split(mut self) -> (Self, Option>) { + unsafe { + if self.end <= self.next_ctrl { + // Nothing to split if the group that we are current processing + // is the last one. + (self, None) + } else { + // len is the remaining number of elements after the group that + // we are currently processing. It must be a multiple of the + // group size (small tables are caught by the check above). + let len = offset_from(self.end, self.next_ctrl); + debug_assert_eq!(len % Group::WIDTH, 0); + + // Split the remaining elements into two halves, but round the + // midpoint down in case there is an odd number of groups + // remaining. This ensures that: + // - The tail is at least 1 group long. + // - The split is roughly even considering we still have the + // current group to process. + let mid = (len / 2) & !(Group::WIDTH - 1); + + let tail = Self::new( + self.next_ctrl.add(mid), + self.data.next_n(Group::WIDTH).next_n(mid), + len - mid, + ); + debug_assert_eq!( + self.data.next_n(Group::WIDTH).next_n(mid).ptr, + tail.data.ptr + ); + debug_assert_eq!(self.end, tail.end); + self.end = self.next_ctrl.add(mid); + debug_assert_eq!(self.end.add(Group::WIDTH), tail.next_ctrl); + (self, Some(tail)) + } + } + } + + /// # Safety + /// If DO_CHECK_PTR_RANGE is false, caller must ensure that we never try to iterate + /// after yielding all elements. + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn next_impl(&mut self) -> Option> { + loop { + if let Some(index) = self.current_group.next() { + return Some(self.data.next_n(index)); + } + + if DO_CHECK_PTR_RANGE && self.next_ctrl >= self.end { + return None; + } + + // We might read past self.end up to the next group boundary, + // but this is fine because it only occurs on tables smaller + // than the group size where the trailing control bytes are all + // EMPTY. On larger tables self.end is guaranteed to be aligned + // to the group size (since tables are power-of-two sized). + self.current_group = Group::load_aligned(self.next_ctrl).match_full().into_iter(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } + + /// Folds every element into an accumulator by applying an operation, + /// returning the final result. + /// + /// `fold_impl()` takes three arguments: the number of items remaining in + /// the iterator, an initial value, and a closure with two arguments: an + /// 'accumulator', and an element. The closure returns the value that the + /// accumulator should have for the next iteration. + /// + /// The initial value is the value the accumulator will have on the first call. + /// + /// After applying this closure to every element of the iterator, `fold_impl()` + /// returns the accumulator. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `RawIterRange`; + /// + /// * The provided `n` value must match the actual number of items + /// in the table. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[allow(clippy::while_let_on_iterator)] + #[cfg_attr(feature = "inline-more", inline)] + unsafe fn fold_impl(mut self, mut n: usize, mut acc: B, mut f: F) -> B + where + F: FnMut(B, Bucket) -> B, + { + loop { + while let Some(index) = self.current_group.next() { + // The returned `index` will always be in the range `0..Group::WIDTH`, + // so that calling `self.data.next_n(index)` is safe (see detailed explanation below). + debug_assert!(n != 0); + let bucket = self.data.next_n(index); + acc = f(acc, bucket); + n -= 1; + } + + if n == 0 { + return acc; + } + + // SAFETY: The caller of this function ensures that: + // + // 1. The provided `n` value matches the actual number of items in the table; + // 2. The table is alive and did not moved. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.current_group` will read bytes + // from the `self.buckets() - Group::WIDTH` index. We know also that + // `self.current_group.next()` will always retun indices within the range + // `0..Group::WIDTH`. + // + // Knowing all of the above and taking into account that we are synchronizing + // the `self.data` index with the index we used to read the `self.current_group`, + // the subsequent `self.data.next_n(index)` will always return a bucket with + // an index number less than `self.buckets()`. + // + // The last `self.next_ctrl`, whose index would be `self.buckets()`, will never + // actually be read, since we should have already yielded all the elements of + // the table. + self.current_group = Group::load_aligned(self.next_ctrl).match_full().into_iter(); + self.data = self.data.next_n(Group::WIDTH); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); + } + } +} + +// We make raw iterators unconditionally Send and Sync, and let the PhantomData +// in the actual iterator implementations determine the real Send/Sync bounds. +unsafe impl Send for RawIterRange {} +unsafe impl Sync for RawIterRange {} + +impl Clone for RawIterRange { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + data: self.data.clone(), + next_ctrl: self.next_ctrl, + current_group: self.current_group, + end: self.end, + } + } +} + +impl Iterator for RawIterRange { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + unsafe { + // SAFETY: We set checker flag to true. + self.next_impl::() + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // We don't have an item count, so just guess based on the range size. + let remaining_buckets = if self.end > self.next_ctrl { + unsafe { offset_from(self.end, self.next_ctrl) } + } else { + 0 + }; + + // Add a group width to include the group we are currently processing. + (0, Some(Group::WIDTH + remaining_buckets)) + } +} + +impl FusedIterator for RawIterRange {} + +/// Iterator which returns a raw pointer to every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket (unless `reflect_remove` is called). +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator (unless `reflect_insert` is called). +/// - The order in which the iterator yields bucket is unspecified and may +/// change in the future. +pub struct RawIter { + pub(crate) iter: RawIterRange, + items: usize, +} + +impl RawIter { + /// Refresh the iterator so that it reflects a removal from the given bucket. + /// + /// For the iterator to remain valid, this method must be called once + /// for each removed bucket before `next` is called again. + /// + /// This method should be called _before_ the removal is made. It is not necessary to call this + /// method if you are removing an item that this iterator yielded in the past. + #[cfg(feature = "raw")] + pub unsafe fn reflect_remove(&mut self, b: &Bucket) { + self.reflect_toggle_full(b, false); + } + + /// Refresh the iterator so that it reflects an insertion into the given bucket. + /// + /// For the iterator to remain valid, this method must be called once + /// for each insert before `next` is called again. + /// + /// This method does not guarantee that an insertion of a bucket with a greater + /// index than the last one yielded will be reflected in the iterator. + /// + /// This method should be called _after_ the given insert is made. + #[cfg(feature = "raw")] + pub unsafe fn reflect_insert(&mut self, b: &Bucket) { + self.reflect_toggle_full(b, true); + } + + /// Refresh the iterator so that it reflects a change to the state of the given bucket. + #[cfg(feature = "raw")] + unsafe fn reflect_toggle_full(&mut self, b: &Bucket, is_insert: bool) { + if b.as_ptr() > self.iter.data.as_ptr() { + // The iterator has already passed the bucket's group. + // So the toggle isn't relevant to this iterator. + return; + } + + if self.iter.next_ctrl < self.iter.end + && b.as_ptr() <= self.iter.data.next_n(Group::WIDTH).as_ptr() + { + // The iterator has not yet reached the bucket's group. + // We don't need to reload anything, but we do need to adjust the item count. + + if cfg!(debug_assertions) { + // Double-check that the user isn't lying to us by checking the bucket state. + // To do that, we need to find its control byte. We know that self.iter.data is + // at self.iter.next_ctrl - Group::WIDTH, so we work from there: + let offset = offset_from(self.iter.data.as_ptr(), b.as_ptr()); + let ctrl = self.iter.next_ctrl.sub(Group::WIDTH).add(offset); + // This method should be called _before_ a removal, or _after_ an insert, + // so in both cases the ctrl byte should indicate that the bucket is full. + assert!(is_full(*ctrl)); + } + + if is_insert { + self.items += 1; + } else { + self.items -= 1; + } + + return; + } + + // The iterator is at the bucket group that the toggled bucket is in. + // We need to do two things: + // + // - Determine if the iterator already yielded the toggled bucket. + // If it did, we're done. + // - Otherwise, update the iterator cached group so that it won't + // yield a to-be-removed bucket, or _will_ yield a to-be-added bucket. + // We'll also need to update the item count accordingly. + if let Some(index) = self.iter.current_group.0.lowest_set_bit() { + let next_bucket = self.iter.data.next_n(index); + if b.as_ptr() > next_bucket.as_ptr() { + // The toggled bucket is "before" the bucket the iterator would yield next. We + // therefore don't need to do anything --- the iterator has already passed the + // bucket in question. + // + // The item count must already be correct, since a removal or insert "prior" to + // the iterator's position wouldn't affect the item count. + } else { + // The removed bucket is an upcoming bucket. We need to make sure it does _not_ + // get yielded, and also that it's no longer included in the item count. + // + // NOTE: We can't just reload the group here, both since that might reflect + // inserts we've already passed, and because that might inadvertently unset the + // bits for _other_ removals. If we do that, we'd have to also decrement the + // item count for those other bits that we unset. But the presumably subsequent + // call to reflect for those buckets might _also_ decrement the item count. + // Instead, we _just_ flip the bit for the particular bucket the caller asked + // us to reflect. + let our_bit = offset_from(self.iter.data.as_ptr(), b.as_ptr()); + let was_full = self.iter.current_group.flip(our_bit); + debug_assert_ne!(was_full, is_insert); + + if is_insert { + self.items += 1; + } else { + self.items -= 1; + } + + if cfg!(debug_assertions) { + if b.as_ptr() == next_bucket.as_ptr() { + // The removed bucket should no longer be next + debug_assert_ne!(self.iter.current_group.0.lowest_set_bit(), Some(index)); + } else { + // We should not have changed what bucket comes next. + debug_assert_eq!(self.iter.current_group.0.lowest_set_bit(), Some(index)); + } + } + } + } else { + // We must have already iterated past the removed item. + } + } + + unsafe fn drop_elements(&mut self) { + if T::NEEDS_DROP && self.items != 0 { + for item in self { + item.drop(); + } + } + } +} + +impl Clone for RawIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + items: self.items, + } + } +} + +impl Iterator for RawIter { + type Item = Bucket; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option> { + // Inner iterator iterates over buckets + // so it can do unnecessary work if we already yielded all items. + if self.items == 0 { + return None; + } + + let nxt = unsafe { + // SAFETY: We check number of items to yield using `items` field. + self.iter.next_impl::() + }; + + debug_assert!(nxt.is_some()); + self.items -= 1; + + nxt + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + unsafe { self.iter.fold_impl(self.items, init, f) } + } +} + +impl ExactSizeIterator for RawIter {} +impl FusedIterator for RawIter {} + +/// Iterator which returns an index of every full bucket in the table. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding index of that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields indices of the buckets is unspecified +/// and may change in the future. +pub(crate) struct FullBucketsIndices { + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. + current_group: BitMaskIter, + + // Initial value of the bytes' indices of the current group (relative + // to the start of the control bytes). + group_first_index: usize, + + // Pointer to the current group of control bytes, + // Must be aligned to the group size (Group::WIDTH). + ctrl: NonNull, + + // Number of elements in the table. + items: usize, +} + +impl FullBucketsIndices { + /// Advances the iterator and returns the next value. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is + /// [`Undefined Behavior`]: + /// + /// * The [`RawTableInner`] / [`RawTable`] must be alive and not moved, + /// i.e. table outlives the `FullBucketsIndices`; + /// + /// * It never tries to iterate after getting all elements. + /// + /// [`Undefined Behavior`]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[inline(always)] + unsafe fn next_impl(&mut self) -> Option { + loop { + if let Some(index) = self.current_group.next() { + // The returned `self.group_first_index + index` will always + // be in the range `0..self.buckets()`. See explanation below. + return Some(self.group_first_index + index); + } + + // SAFETY: The caller of this function ensures that: + // + // 1. It never tries to iterate after getting all the elements; + // 2. The table is alive and did not moved; + // 3. The first `self.ctrl` pointed to the start of the array of control bytes. + // + // Taking the above into account, we always stay within the bounds, because: + // + // 1. For tables smaller than the group width (self.buckets() <= Group::WIDTH), + // we will never end up in the given branch, since we should have already + // yielded all the elements of the table. + // + // 2. For tables larger than the group width. The number of buckets is a + // power of two (2 ^ n), Group::WIDTH is also power of two (2 ^ k). Since + // `(2 ^ n) > (2 ^ k)`, than `(2 ^ n) % (2 ^ k) = 0`. As we start from the + // the start of the array of control bytes, and never try to iterate after + // getting all the elements, the last `self.ctrl` will be equal to + // the `self.buckets() - Group::WIDTH`, so `self.current_group.next()` + // will always contains indices within the range `0..Group::WIDTH`, + // and subsequent `self.group_first_index + index` will always return a + // number less than `self.buckets()`. + self.ctrl = NonNull::new_unchecked(self.ctrl.as_ptr().add(Group::WIDTH)); + + // SAFETY: See explanation above. + self.current_group = Group::load_aligned(self.ctrl.as_ptr()) + .match_full() + .into_iter(); + self.group_first_index += Group::WIDTH; + } + } +} + +impl Iterator for FullBucketsIndices { + type Item = usize; + + /// Advances the iterator and returns the next value. It is up to + /// the caller to ensure that the `RawTable` outlives the `FullBucketsIndices`, + /// because we cannot make the `next` method unsafe. + #[inline(always)] + fn next(&mut self) -> Option { + // Return if we already yielded all items. + if self.items == 0 { + return None; + } + + let nxt = unsafe { + // SAFETY: + // 1. We check number of items to yield using `items` field. + // 2. The caller ensures that the table is alive and has not moved. + self.next_impl() + }; + + debug_assert!(nxt.is_some()); + self.items -= 1; + + nxt + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + (self.items, Some(self.items)) + } +} + +impl ExactSizeIterator for FullBucketsIndices {} +impl FusedIterator for FullBucketsIndices {} + +/// Iterator which consumes a table and returns elements. +pub struct RawIntoIter { + iter: RawIter, + allocation: Option<(NonNull, Layout, A)>, + marker: PhantomData, +} + +impl RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawIntoIter +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawIntoIter +where + T: Sync, + A: Sync, +{ +} + +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); + } + } + } +} +#[cfg(not(feature = "nightly"))] +impl Drop for RawIntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + self.iter.drop_elements(); + + // Free the table + if let Some((ptr, layout, ref alloc)) = self.allocation { + alloc.deallocate(ptr, layout); + } + } + } +} + +impl Iterator for RawIntoIter { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { Some(self.iter.next()?.read()) } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawIntoIter {} +impl FusedIterator for RawIntoIter {} + +/// Iterator which consumes elements without freeing the table storage. +pub struct RawDrain<'a, T, A: Allocator = Global> { + iter: RawIter, + + // The table is moved into the iterator for the duration of the drain. This + // ensures that an empty table is left if the drain iterator is leaked + // without dropping. + table: RawTableInner, + orig_table: NonNull, + + // We don't use a &'a mut RawTable because we want RawDrain to be + // covariant over T. + marker: PhantomData<&'a RawTable>, +} + +impl RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> RawIter { + self.iter.clone() + } +} + +unsafe impl Send for RawDrain<'_, T, A> +where + T: Send, + A: Send, +{ +} +unsafe impl Sync for RawDrain<'_, T, A> +where + T: Sync, + A: Sync, +{ +} + +impl Drop for RawDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements. Note that this may panic. + self.iter.drop_elements(); + + // Reset the contents of the table now that all elements have been + // dropped. + self.table.clear_no_drop(); + + // Move the now empty table back to its original location. + self.orig_table + .as_ptr() + .copy_from_nonoverlapping(&self.table, 1); + } + } +} + +impl Iterator for RawDrain<'_, T, A> { + type Item = T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + unsafe { + let item = self.iter.next()?; + Some(item.read()) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for RawDrain<'_, T, A> {} +impl FusedIterator for RawDrain<'_, T, A> {} + +/// Iterator over occupied buckets that could match a given hash. +/// +/// `RawTable` only stores 7 bits of the hash value, so this iterator may return +/// items that have a hash value different than the one provided. You should +/// always validate the returned values before using them. +/// +/// For maximum flexibility this iterator is not bound by a lifetime, but you +/// must observe several rules when using it: +/// - You must not free the hash table while iterating (including via growing/shrinking). +/// - It is fine to erase a bucket that has been yielded by the iterator. +/// - Erasing a bucket that has not yet been yielded by the iterator may still +/// result in the iterator yielding that bucket. +/// - It is unspecified whether an element inserted after the iterator was +/// created will be yielded by that iterator. +/// - The order in which the iterator yields buckets is unspecified and may +/// change in the future. +pub struct RawIterHash { + inner: RawIterHashInner, + _marker: PhantomData, +} + +struct RawIterHashInner { + // See `RawTableInner`'s corresponding fields for details. + // We can't store a `*const RawTableInner` as it would get + // invalidated by the user calling `&mut` methods on `RawTable`. + bucket_mask: usize, + ctrl: NonNull, + + // The top 7 bits of the hash. + h2_hash: u8, + + // The sequence of groups to probe in the search. + probe_seq: ProbeSeq, + + group: Group, + + // The elements within the group with a matching h2-hash. + bitmask: BitMaskIter, +} + +impl RawIterHash { + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "raw")] + unsafe fn new(table: &RawTable, hash: u64) -> Self { + RawIterHash { + inner: RawIterHashInner::new(&table.table, hash), + _marker: PhantomData, + } + } +} +impl RawIterHashInner { + #[cfg_attr(feature = "inline-more", inline)] + #[cfg(feature = "raw")] + unsafe fn new(table: &RawTableInner, hash: u64) -> Self { + let h2_hash = h2(hash); + let probe_seq = table.probe_seq(hash); + let group = Group::load(table.ctrl(probe_seq.pos)); + let bitmask = group.match_byte(h2_hash).into_iter(); + + RawIterHashInner { + bucket_mask: table.bucket_mask, + ctrl: table.ctrl, + h2_hash, + probe_seq, + group, + bitmask, + } + } +} + +impl Iterator for RawIterHash { + type Item = Bucket; + + fn next(&mut self) -> Option> { + unsafe { + match self.inner.next() { + Some(index) => { + // Can't use `RawTable::bucket` here as we don't have + // an actual `RawTable` reference to use. + debug_assert!(index <= self.inner.bucket_mask); + let bucket = Bucket::from_base_index(self.inner.ctrl.cast(), index); + Some(bucket) + } + None => None, + } + } + } +} + +impl Iterator for RawIterHashInner { + type Item = usize; + + fn next(&mut self) -> Option { + unsafe { + loop { + if let Some(bit) = self.bitmask.next() { + let index = (self.probe_seq.pos + bit) & self.bucket_mask; + return Some(index); + } + if likely(self.group.match_empty().any_bit_set()) { + return None; + } + self.probe_seq.move_next(self.bucket_mask); + + // Can't use `RawTableInner::ctrl` here as we don't have + // an actual `RawTableInner` reference to use. + let index = self.probe_seq.pos; + debug_assert!(index < self.bucket_mask + 1 + Group::WIDTH); + let group_ctrl = self.ctrl.as_ptr().add(index); + + self.group = Group::load(group_ctrl); + self.bitmask = self.group.match_byte(self.h2_hash).into_iter(); + } + } + } +} + +pub(crate) struct RawExtractIf<'a, T, A: Allocator> { + pub iter: RawIter, + pub table: &'a mut RawTable, +} + +impl RawExtractIf<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(crate) fn next(&mut self, mut f: F) -> Option + where + F: FnMut(&mut T) -> bool, + { + unsafe { + for item in &mut self.iter { + if f(item.as_mut()) { + return Some(self.table.remove(item).0); + } + } + } + None + } +} + +#[cfg(test)] +mod test_map { + use super::*; + + fn rehash_in_place(table: &mut RawTable, hasher: impl Fn(&T) -> u64) { + unsafe { + table.table.rehash_in_place( + &|table, index| hasher(table.bucket::(index).as_ref()), + mem::size_of::(), + if mem::needs_drop::() { + Some(mem::transmute(ptr::drop_in_place:: as unsafe fn(*mut T))) + } else { + None + }, + ); + } + } + + #[test] + fn rehash() { + let mut table = RawTable::new(); + let hasher = |i: &u64| *i; + for i in 0..100 { + table.insert(i, i, hasher); + } + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + + rehash_in_place(&mut table, hasher); + + for i in 0..100 { + unsafe { + assert_eq!(table.find(i, |x| *x == i).map(|b| b.read()), Some(i)); + } + assert!(table.find(i + 100, |x| *x == i + 100).is_none()); + } + } + + /// CHECKING THAT WE ARE NOT TRYING TO READ THE MEMORY OF + /// AN UNINITIALIZED TABLE DURING THE DROP + #[test] + fn test_drop_uninitialized() { + use ::alloc::vec::Vec; + + let table = unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap() + }; + drop(table); + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + fn test_drop_zero_items() { + use ::alloc::vec::Vec; + unsafe { + // SAFETY: The `buckets` is power of two and we're not + // trying to actually use the returned RawTable. + let table = + RawTable::<(u64, Vec)>::new_uninitialized(Global, 8, Fallibility::Infallible) + .unwrap(); + + // WE SIMULATE, AS IT WERE, A FULL TABLE. + + // SAFETY: We checked that the table is allocated and therefore the table already has + // `self.bucket_mask + 1 + Group::WIDTH` number of control bytes (see TableLayout::calculate_layout_for) + // so writing `table.table.num_ctrl_bytes() == bucket_mask + 1 + Group::WIDTH` bytes is safe. + table + .table + .ctrl(0) + .write_bytes(EMPTY, table.table.num_ctrl_bytes()); + + // SAFETY: table.capacity() is guaranteed to be smaller than table.buckets() + table.table.ctrl(0).write_bytes(0, table.capacity()); + + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. + if table.buckets() < Group::WIDTH { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of control bytes, + // so copying `self.buckets() == self.bucket_mask + 1` bytes with offset equal to + // `Group::WIDTH` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(Group::WIDTH), table.table.buckets()); + } else { + // SAFETY: We have `self.bucket_mask + 1 + Group::WIDTH` number of + // control bytes,so copying `Group::WIDTH` bytes with offset equal + // to `self.buckets() == self.bucket_mask + 1` is safe + table + .table + .ctrl(0) + .copy_to(table.table.ctrl(table.table.buckets()), Group::WIDTH); + } + drop(table); + } + } + + /// CHECKING THAT WE DON'T TRY TO DROP DATA IF THE `ITEMS` + /// ARE ZERO, EVEN IF WE HAVE `FULL` CONTROL BYTES. + #[test] + fn test_catch_panic_clone_from() { + use ::alloc::sync::Arc; + use ::alloc::vec::Vec; + use allocator_api2::alloc::{AllocError, Allocator, Global}; + use core::sync::atomic::{AtomicI8, Ordering}; + use std::thread; + + struct MyAllocInner { + drop_count: Arc, + } + + #[derive(Clone)] + struct MyAlloc { + _inner: Arc, + } + + impl Drop for MyAllocInner { + fn drop(&mut self) { + println!("MyAlloc freed."); + self.drop_count.fetch_sub(1, Ordering::SeqCst); + } + } + + unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> std::result::Result, AllocError> { + let g = Global; + g.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + let g = Global; + g.deallocate(ptr, layout) + } + } + + const DISARMED: bool = false; + const ARMED: bool = true; + + struct CheckedCloneDrop { + panic_in_clone: bool, + dropped: bool, + need_drop: Vec, + } + + impl Clone for CheckedCloneDrop { + fn clone(&self) -> Self { + if self.panic_in_clone { + panic!("panic in clone") + } + Self { + panic_in_clone: self.panic_in_clone, + dropped: self.dropped, + need_drop: self.need_drop.clone(), + } + } + } + + impl Drop for CheckedCloneDrop { + fn drop(&mut self) { + if self.dropped { + panic!("double drop"); + } + self.dropped = true; + } + } + + let dropped: Arc = Arc::new(AtomicI8::new(2)); + + let mut table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + + for (idx, panic_in_clone) in core::iter::repeat(DISARMED).take(7).enumerate() { + let idx = idx as u64; + table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx], + }, + ), + |(k, _)| *k, + ); + } + + assert_eq!(table.len(), 7); + + thread::scope(|s| { + let result = s.spawn(|| { + let armed_flags = [ + DISARMED, DISARMED, ARMED, DISARMED, DISARMED, DISARMED, DISARMED, + ]; + let mut scope_table = RawTable::new_in(MyAlloc { + _inner: Arc::new(MyAllocInner { + drop_count: dropped.clone(), + }), + }); + for (idx, &panic_in_clone) in armed_flags.iter().enumerate() { + let idx = idx as u64; + scope_table.insert( + idx, + ( + idx, + CheckedCloneDrop { + panic_in_clone, + dropped: false, + need_drop: vec![idx + 100], + }, + ), + |(k, _)| *k, + ); + } + table.clone_from(&scope_table); + }); + assert!(result.join().is_err()); + }); + + // Let's check that all iterators work fine and do not return elements + // (especially `RawIterRange`, which does not depend on the number of + // elements in the table, but looks directly at the control bytes) + // + // SAFETY: We know for sure that `RawTable` will outlive + // the returned `RawIter / RawIterRange` iterator. + assert_eq!(table.len(), 0); + assert_eq!(unsafe { table.iter().count() }, 0); + assert_eq!(unsafe { table.iter().iter.count() }, 0); + + for idx in 0..table.buckets() { + let idx = idx as u64; + assert!( + table.find(idx, |(k, _)| *k == idx).is_none(), + "Index: {idx}" + ); + } + + // All allocator clones should already be dropped. + assert_eq!(dropped.load(Ordering::SeqCst), 1); + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/raw/neon.rs b/third_party/crates/hashbrown-0.14.5/src/raw/neon.rs new file mode 100644 index 0000000..44e82d5 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/raw/neon.rs @@ -0,0 +1,124 @@ +use super::bitmask::BitMask; +use super::EMPTY; +use core::arch::aarch64 as neon; +use core::mem; +use core::num::NonZeroU64; + +pub(crate) type BitMaskWord = u64; +pub(crate) type NonZeroBitMaskWord = NonZeroU64; +pub(crate) const BITMASK_STRIDE: usize = 8; +pub(crate) const BITMASK_MASK: BitMaskWord = !0; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = 0x8080_8080_8080_8080; + +/// Abstraction over a group of control bytes which can be scanned in +/// parallel. +/// +/// This implementation uses a 64-bit NEON value. +#[derive(Copy, Clone)] +pub(crate) struct Group(neon::uint8x8_t); + +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty bytes, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], + bytes: [u8; Group::WIDTH], + } + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], + bytes: [EMPTY; Group::WIDTH], + }; + &ALIGNED_BYTES.bytes + } + + /// Loads a group of bytes starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const u8) -> Self { + Group(neon::vld1_u8(ptr)) + } + + /// Loads a group of bytes starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + Group(neon::vld1_u8(ptr)) + } + + /// Stores the group of bytes to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + neon::vst1_u8(ptr, self.0); + } + + /// Returns a `BitMask` indicating all bytes in the group which *may* + /// have the given value. + #[inline] + pub(crate) fn match_byte(self, byte: u8) -> BitMask { + unsafe { + let cmp = neon::vceq_u8(self.0, neon::vdup_n_u8(byte)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + self.match_byte(EMPTY) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + unsafe { + let cmp = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub(crate) fn match_full(self) -> BitMask { + unsafe { + let cmp = neon::vcgez_s8(neon::vreinterpret_s8_u8(self.0)); + BitMask(neon::vget_lane_u64(neon::vreinterpret_u64_u8(cmp), 0)) + } + } + + /// Performs the following transformation on all bytes in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > byte = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + unsafe { + let special = neon::vcltz_s8(neon::vreinterpret_s8_u8(self.0)); + Group(neon::vorr_u8(special, neon::vdup_n_u8(0x80))) + } + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/raw/sse2.rs b/third_party/crates/hashbrown-0.14.5/src/raw/sse2.rs new file mode 100644 index 0000000..956ba5d --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/raw/sse2.rs @@ -0,0 +1,149 @@ +use super::bitmask::BitMask; +use super::EMPTY; +use core::mem; +use core::num::NonZeroU16; + +#[cfg(target_arch = "x86")] +use core::arch::x86; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64 as x86; + +pub(crate) type BitMaskWord = u16; +pub(crate) type NonZeroBitMaskWord = NonZeroU16; +pub(crate) const BITMASK_STRIDE: usize = 1; +pub(crate) const BITMASK_MASK: BitMaskWord = 0xffff; +pub(crate) const BITMASK_ITER_MASK: BitMaskWord = !0; + +/// Abstraction over a group of control bytes which can be scanned in +/// parallel. +/// +/// This implementation uses a 128-bit SSE value. +#[derive(Copy, Clone)] +pub(crate) struct Group(x86::__m128i); + +// FIXME: https://github.com/rust-lang/rust-clippy/issues/3859 +#[allow(clippy::use_self)] +impl Group { + /// Number of bytes in the group. + pub(crate) const WIDTH: usize = mem::size_of::(); + + /// Returns a full group of empty bytes, suitable for use as the initial + /// value for an empty hash table. + /// + /// This is guaranteed to be aligned to the group size. + #[inline] + #[allow(clippy::items_after_statements)] + pub(crate) const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], + bytes: [u8; Group::WIDTH], + } + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], + bytes: [EMPTY; Group::WIDTH], + }; + &ALIGNED_BYTES.bytes + } + + /// Loads a group of bytes starting at the given address. + #[inline] + #[allow(clippy::cast_ptr_alignment)] // unaligned load + pub(crate) unsafe fn load(ptr: *const u8) -> Self { + Group(x86::_mm_loadu_si128(ptr.cast())) + } + + /// Loads a group of bytes starting at the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn load_aligned(ptr: *const u8) -> Self { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + Group(x86::_mm_load_si128(ptr.cast())) + } + + /// Stores the group of bytes to the given address, which must be + /// aligned to `mem::align_of::()`. + #[inline] + #[allow(clippy::cast_ptr_alignment)] + pub(crate) unsafe fn store_aligned(self, ptr: *mut u8) { + // FIXME: use align_offset once it stabilizes + debug_assert_eq!(ptr as usize & (mem::align_of::() - 1), 0); + x86::_mm_store_si128(ptr.cast(), self.0); + } + + /// Returns a `BitMask` indicating all bytes in the group which have + /// the given value. + #[inline] + pub(crate) fn match_byte(self, byte: u8) -> BitMask { + #[allow( + clippy::cast_possible_wrap, // byte: u8 as i8 + // byte: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + let cmp = x86::_mm_cmpeq_epi8(self.0, x86::_mm_set1_epi8(byte as i8)); + BitMask(x86::_mm_movemask_epi8(cmp) as u16) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY`. + #[inline] + pub(crate) fn match_empty(self) -> BitMask { + self.match_byte(EMPTY) + } + + /// Returns a `BitMask` indicating all bytes in the group which are + /// `EMPTY` or `DELETED`. + #[inline] + pub(crate) fn match_empty_or_deleted(self) -> BitMask { + #[allow( + // byte: i32 as u16 + // note: _mm_movemask_epi8 returns a 16-bit mask in a i32, the + // upper 16-bits of the i32 are zeroed: + clippy::cast_sign_loss, + clippy::cast_possible_truncation + )] + unsafe { + // A byte is EMPTY or DELETED iff the high bit is set + BitMask(x86::_mm_movemask_epi8(self.0) as u16) + } + } + + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub(crate) fn match_full(&self) -> BitMask { + self.match_empty_or_deleted().invert() + } + + /// Performs the following transformation on all bytes in the group: + /// - `EMPTY => EMPTY` + /// - `DELETED => EMPTY` + /// - `FULL => DELETED` + #[inline] + pub(crate) fn convert_special_to_empty_and_full_to_deleted(self) -> Self { + // Map high_bit = 1 (EMPTY or DELETED) to 1111_1111 + // and high_bit = 0 (FULL) to 1000_0000 + // + // Here's this logic expanded to concrete values: + // let special = 0 > byte = 1111_1111 (true) or 0000_0000 (false) + // 1111_1111 | 1000_0000 = 1111_1111 + // 0000_0000 | 1000_0000 = 1000_0000 + #[allow( + clippy::cast_possible_wrap, // byte: 0x80_u8 as i8 + )] + unsafe { + let zero = x86::_mm_setzero_si128(); + let special = x86::_mm_cmpgt_epi8(zero, self.0); + Group(x86::_mm_or_si128( + special, + x86::_mm_set1_epi8(0x80_u8 as i8), + )) + } + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/rustc_entry.rs b/third_party/crates/hashbrown-0.14.5/src/rustc_entry.rs new file mode 100644 index 0000000..defbd4b --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/rustc_entry.rs @@ -0,0 +1,630 @@ +use self::RustcEntry::*; +use crate::map::{make_hash, Drain, HashMap, IntoIter, Iter, IterMut}; +use crate::raw::{Allocator, Bucket, Global, RawTable}; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::mem; + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.rustc_entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> { + let hash = make_hash(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { + RustcEntry::Occupied(RustcOccupiedEntry { + key: Some(key), + elem, + table: &mut self.table, + }) + } else { + // Ideally we would put this in VacantEntry::insert, but Entry is not + // generic over the BuildHasher and adding a generic parameter would be + // a breaking change. + self.reserve(1); + + RustcEntry::Vacant(RustcVacantEntry { + hash, + key, + table: &mut self.table, + }) + } + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`rustc_entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`rustc_entry`]: struct.HashMap.html#method.rustc_entry +pub enum RustcEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + Occupied(RustcOccupiedEntry<'a, K, V, A>), + + /// A vacant entry. + Vacant(RustcVacantEntry<'a, K, V, A>), +} + +impl Debug for RustcEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcOccupiedEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + key: Option, + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V), A>, +} + +unsafe impl Send for RustcOccupiedEntry<'_, K, V, A> +where + K: Send, + V: Send, + A: Allocator + Send, +{ +} +unsafe impl Sync for RustcOccupiedEntry<'_, K, V, A> +where + K: Sync, + V: Sync, + A: Allocator + Sync, +{ +} + +impl Debug for RustcOccupiedEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcVacantEntry<'a, K, V, A = Global> +where + A: Allocator, +{ + hash: u64, + key: K, + table: &'a mut RawTable<(K, V), A>, +} + +impl Debug for RustcVacantEntry<'_, K, V, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +impl<'a, K, V, A: Allocator> RustcEntry<'a, K, V, A> { + /// Sets the value of the entry, and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// let entry = map.rustc_entry("horseyland").insert(37); + /// + /// assert_eq!(entry.key(), &"horseyland"); + /// ``` + pub fn insert(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + match self { + Vacant(entry) => entry.insert_entry(value), + Occupied(mut entry) => { + entry.insert(value); + entry + } + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.rustc_entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.rustc_entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + } + Vacant(entry) => Vacant(entry), + } + } +} + +impl<'a, K, V: Default, A: Allocator> RustcEntry<'a, K, V, A> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// map.rustc_entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V, A: Allocator> RustcOccupiedEntry<'a, K, V, A> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove_entry(self) -> (K, V) { + unsafe { self.table.remove(self.elem).0 } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `RustcOccupiedEntry` which may outlive the + /// destruction of the `RustcEntry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same RustcEntry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the RustcOccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `RustcOccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{RustcEntry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(Rc::new("Stringthing".to_string()), 15); + /// + /// let my_key = Rc::new("Stringthing".to_string()); + /// + /// if let RustcEntry::Occupied(entry) = map.rustc_entry(my_key) { + /// // Also replace the key with a handle to our other key. + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// } + /// + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry(self, value: V) -> (K, V) { + let entry = unsafe { self.elem.as_mut() }; + + let old_key = mem::replace(&mut entry.0, self.key.unwrap()); + let old_value = mem::replace(&mut entry.1, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{RustcEntry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let mut known_strings: Vec> = Vec::new(); + /// + /// // Initialise known strings, run program, etc. + /// + /// reclaim_memory(&mut map, &known_strings); + /// + /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { + /// for s in known_strings { + /// if let RustcEntry::Occupied(entry) = map.rustc_entry(s.clone()) { + /// // Replaces the entry's key with our version of it in `known_strings`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_key(self) -> K { + let entry = unsafe { self.elem.as_mut() }; + mem::replace(&mut entry.0, self.key.unwrap()) + } +} + +impl<'a, K, V, A: Allocator> RustcVacantEntry<'a, K, V, A> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `RustcVacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(o) = map.rustc_entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self, value: V) -> &'a mut V { + unsafe { + let bucket = self.table.insert_no_grow(self.hash, (self.key, value)); + &mut bucket.as_mut().1 + } + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a RustcOccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// let o = v.insert_entry(37); + /// assert_eq!(o.get(), &37); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_entry(self, value: V) -> RustcOccupiedEntry<'a, K, V, A> { + let bucket = unsafe { self.table.insert_no_grow(self.hash, (self.key, value)) }; + RustcOccupiedEntry { + key: None, + elem: bucket, + table: self.table, + } + } +} + +impl IterMut<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} + +impl Drain<'_, K, V> { + /// Returns a iterator of references over the remaining items. + #[cfg_attr(feature = "inline-more", inline)] + pub fn rustc_iter(&self) -> Iter<'_, K, V> { + self.iter() + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/scopeguard.rs b/third_party/crates/hashbrown-0.14.5/src/scopeguard.rs new file mode 100644 index 0000000..382d060 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/scopeguard.rs @@ -0,0 +1,72 @@ +// Extracted from the scopeguard crate +use core::{ + mem::ManuallyDrop, + ops::{Deref, DerefMut}, + ptr, +}; + +pub struct ScopeGuard +where + F: FnMut(&mut T), +{ + dropfn: F, + value: T, +} + +#[inline] +pub fn guard(value: T, dropfn: F) -> ScopeGuard +where + F: FnMut(&mut T), +{ + ScopeGuard { dropfn, value } +} + +impl ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + pub fn into_inner(guard: Self) -> T { + // Cannot move out of Drop-implementing types, so + // ptr::read the value out of a ManuallyDrop + // Don't use mem::forget as that might invalidate value + let guard = ManuallyDrop::new(guard); + unsafe { + let value = ptr::read(&guard.value); + // read the closure so that it is dropped + let _ = ptr::read(&guard.dropfn); + value + } + } +} + +impl Deref for ScopeGuard +where + F: FnMut(&mut T), +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + &self.value + } +} + +impl DerefMut for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl Drop for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn drop(&mut self) { + (self.dropfn)(&mut self.value); + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/set.rs b/third_party/crates/hashbrown-0.14.5/src/set.rs new file mode 100644 index 0000000..2125a7a --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/set.rs @@ -0,0 +1,2970 @@ +#[cfg(feature = "raw")] +use crate::raw::RawTable; +use crate::{Equivalent, TryReserveError}; +use alloc::borrow::ToOwned; +use core::fmt; +use core::hash::{BuildHasher, Hash}; +use core::iter::{Chain, FusedIterator}; +use core::ops::{BitAnd, BitOr, BitXor, Sub}; + +use super::map::{self, DefaultHashBuilder, HashMap, Keys}; +use crate::raw::{Allocator, Global, RawExtractIf}; + +// Future Optimization (FIXME!) +// ============================= +// +// Iteration over zero sized values is a noop. There is no need +// for `bucket.val` in the case of HashSet. I suppose we would need HKT +// to get rid of it properly. + +/// A hash set implemented as a `HashMap` where the value is `()`. +/// +/// As with the [`HashMap`] type, a `HashSet` requires that the elements +/// implement the [`Eq`] and [`Hash`] traits. This can frequently be achieved by +/// using `#[derive(PartialEq, Eq, Hash)]`. If you implement these yourself, +/// it is important that the following property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must be equal. +/// +/// +/// It is a logic error for an item to be modified in such a way that the +/// item's hash, as determined by the [`Hash`] trait, or its equality, as +/// determined by the [`Eq`] trait, changes while it is in the set. This is +/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or +/// unsafe code. +/// +/// It is also a logic error for the [`Hash`] implementation of a key to panic. +/// This is generally only possible if the trait is implemented manually. If a +/// panic does occur then the contents of the `HashSet` may become corrupted and +/// some items may be dropped from the table. +/// +/// # Examples +/// +/// ``` +/// use hashbrown::HashSet; +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashSet` in this example). +/// let mut books = HashSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons".to_string()); +/// books.insert("To Kill a Mockingbird".to_string()); +/// books.insert("The Odyssey".to_string()); +/// books.insert("The Great Gatsby".to_string()); +/// +/// // Check for a specific one. +/// if !books.contains("The Winds of Winter") { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove("The Odyssey"); +/// +/// // Iterate over everything. +/// for book in &books { +/// println!("{}", book); +/// } +/// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// [`Eq`] and [`Hash`]. We must also derive [`PartialEq`]. This will in the +/// future be implied by [`Eq`]. +/// +/// ``` +/// use hashbrown::HashSet; +/// #[derive(Hash, Eq, PartialEq, Debug)] +/// struct Viking { +/// name: String, +/// power: usize, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Einar".to_string(), power: 9 }); +/// vikings.insert(Viking { name: "Olaf".to_string(), power: 4 }); +/// vikings.insert(Viking { name: "Harald".to_string(), power: 8 }); +/// +/// // Use derived implementation to print the vikings. +/// for x in &vikings { +/// println!("{:?}", x); +/// } +/// ``` +/// +/// A `HashSet` with fixed list of elements can be initialized from an array: +/// +/// ``` +/// use hashbrown::HashSet; +/// +/// let viking_names: HashSet<&'static str> = +/// [ "Einar", "Olaf", "Harald" ].into_iter().collect(); +/// // use the values stored in the set +/// ``` +/// +/// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html +/// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html +/// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html +/// [`HashMap`]: struct.HashMap.html +/// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +/// [`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html +pub struct HashSet { + pub(crate) map: HashMap, +} + +impl Clone for HashSet { + fn clone(&self) -> Self { + HashSet { + map: self.map.clone(), + } + } + + fn clone_from(&mut self, source: &Self) { + self.map.clone_from(&source.map); + } +} + +#[cfg(feature = "ahash")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher`](HashSet::with_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new() -> Self { + Self { + map: HashMap::new(), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher`](HashSet::with_capacity_and_hasher) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity(capacity: usize) -> Self { + Self { + map: HashMap::with_capacity(capacity), + } + } +} + +#[cfg(feature = "ahash")] +impl HashSet { + /// Creates an empty `HashSet`. + /// + /// The hash set is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_hasher_in`](HashSet::with_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::new(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn new_in(alloc: A) -> Self { + Self { + map: HashMap::new_in(alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`], for example with + /// [`with_capacity_and_hasher_in`](HashSet::with_capacity_and_hasher_in) method. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_in(capacity, alloc), + } + } +} + +impl HashSet { + /// Returns the number of elements the set can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(100); + /// assert!(set.capacity() >= 100); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn iter(&self) -> Iter<'_, T> { + Iter { + iter: self.map.keys(), + } + } + + /// Returns the number of elements in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1); + /// assert!(!v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert!(!set.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in set.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(set.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + iter: self.map.drain(), + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let xs = [1,2,3,4,5,6]; + /// let mut set: HashSet = xs.into_iter().collect(); + /// set.retain(|&k| k % 2 == 0); + /// assert_eq!(set.len(), 3); + /// ``` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.map.retain(|k, _| f(k)); + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashSet::retain + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = (0..8).collect(); + /// let drained: HashSet = set.extract_if(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&T) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.map.table.iter() }, + table: &mut self.map.table, + }, + } + } + + /// Clears the set, removing all values. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// v.insert(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn clear(&mut self) { + self.map.clear(); + } +} + +impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher(hasher: S) -> Self { + Self { + map: HashMap::with_hasher(hasher), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { + Self { + map: HashMap::with_capacity_and_hasher(capacity, hasher), + } + } +} + +impl HashSet +where + A: Allocator, +{ + /// Returns a reference to the underlying allocator. + #[inline] + pub fn allocator(&self) -> &A { + self.map.allocator() + } + + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is initially created with a capacity of 0, so it will not + /// allocate until it is first inserted into. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher_in(hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_hasher_in(hasher, alloc), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// # HashDoS resistance + /// + /// The `hash_builder` normally use a fixed key by default and that does + /// not allow the `HashSet` to be protected against attacks such as [`HashDoS`]. + /// Users who require HashDoS resistance should explicitly use + /// [`ahash::RandomState`] or [`std::collections::hash_map::RandomState`] + /// as the hasher when creating a [`HashSet`]. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashSet to be useful, see its documentation for details. + /// + /// [`HashDoS`]: https://en.wikipedia.org/wiki/Collision_attack + /// [`std::collections::hash_map::RandomState`]: https://doc.rust-lang.org/std/collections/hash_map/struct.RandomState.html + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> Self { + Self { + map: HashMap::with_capacity_and_hasher_in(capacity, hasher, alloc), + } + } + + /// Returns a reference to the set's [`BuildHasher`]. + /// + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let set: HashSet = HashSet::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = set.hasher(); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn hasher(&self) -> &S { + self.map.hasher() + } +} + +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashSet::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.reserve(10); + /// assert!(set.capacity() >= 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn reserve(&mut self, additional: usize) { + self.map.reserve(additional); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashSet`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.map.try_reserve(additional) + } + + /// Shrinks the capacity of the set as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to_fit(); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to_fit(&mut self) { + self.map.shrink_to_fit(); + } + + /// Shrinks the capacity of the set with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::with_capacity(100); + /// set.insert(1); + /// set.insert(2); + /// assert!(set.capacity() >= 100); + /// set.shrink_to(10); + /// assert!(set.capacity() >= 10); + /// set.shrink_to(0); + /// assert!(set.capacity() >= 2); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.map.shrink_to(min_capacity); + } + + /// Visits the values representing the difference, + /// i.e., the values that are in `self` but not in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Can be seen as `a - b`. + /// for x in a.difference(&b) { + /// println!("{}", x); // Print 1 + /// } + /// + /// let diff: HashSet<_> = a.difference(&b).collect(); + /// assert_eq!(diff, [1].iter().collect()); + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else: + /// let diff: HashSet<_> = b.difference(&a).collect(); + /// assert_eq!(diff, [4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, T, S, A> { + Difference { + iter: self.iter(), + other, + } + } + + /// Visits the values representing the symmetric difference, + /// i.e., the values that are in `self` or in `other` but not in both. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 1, 4 in arbitrary order. + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// + /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect(); + /// let diff2: HashSet<_> = b.symmetric_difference(&a).collect(); + /// + /// assert_eq!(diff1, diff2); + /// assert_eq!(diff1, [1, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, T, S, A> { + SymmetricDifference { + iter: self.difference(other).chain(other.difference(self)), + } + } + + /// Visits the values representing the intersection, + /// i.e., the values that are both in `self` and `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 2, 3 in arbitrary order. + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// + /// let intersection: HashSet<_> = a.intersection(&b).collect(); + /// assert_eq!(intersection, [2, 3].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, T, S, A> { + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Intersection { + iter: smaller.iter(), + other: larger, + } + } + + /// Visits the values representing the union, + /// i.e., all the values in `self` or `other`, without duplicates. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = [4, 2, 3, 4].into_iter().collect(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order. + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// + /// let union: HashSet<_> = a.union(&b).collect(); + /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, T, S, A> { + // We'll iterate one set in full, and only the remaining difference from the other. + // Use the smaller set for the difference in order to reduce hash lookups. + let (smaller, larger) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + Union { + iter: larger.iter().chain(smaller.difference(larger)), + } + } + + /// Returns `true` if the set contains a value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn contains(&self, value: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.map.contains_key(value) + } + + /// Returns a reference to the value in the set, if any, that is equal to the given value. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.get(&2), Some(&2)); + /// assert_eq!(set.get(&4), None); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self, value: &Q) -> Option<&T> + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.get_key_value(value) { + Some((k, _)) => Some(k), + None => None, + } + } + + /// Inserts the given `value` into the set if it is not present, then + /// returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.len(), 3); + /// assert_eq!(set.get_or_insert(2), &2); + /// assert_eq!(set.get_or_insert(100), &100); + /// assert_eq!(set.len(), 4); // 100 was inserted + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert(&mut self, value: T) -> &T { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map + .raw_entry_mut() + .from_key(&value) + .or_insert(value, ()) + .0 + } + + /// Inserts an owned copy of the given `value` into the set if it is not + /// present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_owned(pet); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[inline] + pub fn get_or_insert_owned(&mut self, value: &Q) -> &T + where + Q: Hash + Equivalent + ToOwned, + { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map + .raw_entry_mut() + .from_key(value) + .or_insert_with(|| (value.to_owned(), ())) + .0 + } + + /// Inserts a value computed from `f` into the set if the given `value` is + /// not present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_with(pet, str::to_owned); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + where + Q: Hash + Equivalent, + F: FnOnce(&Q) -> T, + { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map + .raw_entry_mut() + .from_key(value) + .or_insert_with(|| (f(value), ())) + .0 + } + + /// Gets the given value's corresponding entry in the set for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry::*; + /// + /// let mut singles = HashSet::new(); + /// let mut dupes = HashSet::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// if let Vacant(dupe_entry) = dupes.entry(ch) { + /// // We haven't already seen a duplicate, so + /// // check if we've at least seen it once. + /// match singles.entry(ch) { + /// Vacant(single_entry) => { + /// // We found a new character for the first time. + /// single_entry.insert() + /// } + /// Occupied(single_entry) => { + /// // We've already seen this once, "move" it to dupes. + /// single_entry.remove(); + /// dupe_entry.insert(); + /// } + /// } + /// } + /// } + /// + /// assert!(!singles.contains(&'t') && dupes.contains(&'t')); + /// assert!(singles.contains(&'u') && !dupes.contains(&'u')); + /// assert!(!singles.contains(&'v') && !dupes.contains(&'v')); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry(&mut self, value: T) -> Entry<'_, T, S, A> { + match self.map.entry(value) { + map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { inner: entry }), + map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { inner: entry }), + } + } + + /// Returns `true` if `self` has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let mut b = HashSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + pub fn is_disjoint(&self, other: &Self) -> bool { + self.iter().all(|v| !other.contains(v)) + } + + /// Returns `true` if the set is a subset of another, + /// i.e., `other` contains at least all the values in `self`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sup: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + pub fn is_subset(&self, other: &Self) -> bool { + self.len() <= other.len() && self.iter().all(|v| other.contains(v)) + } + + /// Returns `true` if the set is a superset of another, + /// i.e., `self` contains at least all the values in `other`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let sub: HashSet<_> = [1, 2].into_iter().collect(); + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(0); + /// set.insert(1); + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(2); + /// assert_eq!(set.is_superset(&sub), true); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn is_superset(&self, other: &Self) -> bool { + other.is_subset(self) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, `true` is returned. + /// + /// If the set did have this value present, `false` is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert(2), true); + /// assert_eq!(set.insert(2), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(&mut self, value: T) -> bool { + self.map.insert(value, ()).is_none() + } + + /// Insert a value the set without checking if the value already exists in the set. + /// + /// Returns a reference to the value just inserted. + /// + /// This operation is safe if a value does not exist in the set. + /// + /// However, if a value exists in the set already, the behavior is unspecified: + /// this operation may panic, loop forever, or any following operation with the set + /// may panic, loop forever or return arbitrary result. + /// + /// That said, this operation (and following operations) are guaranteed to + /// not violate memory safety. + /// + /// This operation is faster than regular insert, because it does not perform + /// lookup before insertion. + /// + /// This operation is useful during initial population of the set. + /// For example, when constructing a set from another set, we know + /// that values are unique. + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert_unique_unchecked(&mut self, value: T) -> &T { + self.map.insert_unique_unchecked(value, ()).0 + } + + /// Adds a value to the set, replacing the existing value, if any, that is equal to the given + /// one. Returns the replaced value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.insert(Vec::::new()); + /// + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0); + /// set.replace(Vec::with_capacity(10)); + /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 10); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace(&mut self, value: T) -> Option { + match self.map.entry(value) { + map::Entry::Occupied(occupied) => Some(occupied.replace_key()), + map::Entry::Vacant(vacant) => { + vacant.insert(()); + None + } + } + } + + /// Removes a value from the set. Returns whether the value was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// set.insert(2); + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(&mut self, value: &Q) -> bool + where + Q: Hash + Equivalent, + { + self.map.remove(value).is_some() + } + + /// Removes and returns the value in the set, if any, that is equal to the given one. + /// + /// The value may be any borrowed form of the set's value type, but + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for + /// the value type. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].into_iter().collect(); + /// assert_eq!(set.take(&2), Some(2)); + /// assert_eq!(set.take(&2), None); + /// ``` + /// + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// [`Hash`]: https://doc.rust-lang.org/std/hash/trait.Hash.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn take(&mut self, value: &Q) -> Option + where + Q: Hash + Equivalent, + { + // Avoid `Option::map` because it bloats LLVM IR. + match self.map.remove_entry(value) { + Some((k, _)) => Some(k), + None => None, + } + } +} + +impl HashSet { + /// Returns a reference to the [`RawTable`] used underneath [`HashSet`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// # Note + /// + /// Calling this function is safe, but using the raw hash table API may require + /// unsafe functions or blocks. + /// + /// `RawTable` API gives the lowest level of control under the set that can be useful + /// for extending the HashSet's API, but may lead to *[undefined behavior]*. + /// + /// [`HashSet`]: struct.HashSet.html + /// [`RawTable`]: crate::raw::RawTable + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table(&self) -> &RawTable<(T, ()), A> { + self.map.raw_table() + } + + /// Returns a mutable reference to the [`RawTable`] used underneath [`HashSet`]. + /// This function is only available if the `raw` feature of the crate is enabled. + /// + /// # Note + /// + /// Calling this function is safe, but using the raw hash table API may require + /// unsafe functions or blocks. + /// + /// `RawTable` API gives the lowest level of control under the set that can be useful + /// for extending the HashSet's API, but may lead to *[undefined behavior]*. + /// + /// [`HashSet`]: struct.HashSet.html + /// [`RawTable`]: crate::raw::RawTable + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[cfg(feature = "raw")] + #[cfg_attr(feature = "inline-more", inline)] + pub fn raw_table_mut(&mut self) -> &mut RawTable<(T, ()), A> { + self.map.raw_table_mut() + } +} + +impl PartialEq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn eq(&self, other: &Self) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().all(|key| other.contains(key)) + } +} + +impl Eq for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for HashSet +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +impl From> for HashSet +where + A: Allocator, +{ + fn from(map: HashMap) -> Self { + Self { map } + } +} + +impl FromIterator for HashSet +where + T: Eq + Hash, + S: BuildHasher + Default, + A: Default + Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn from_iter>(iter: I) -> Self { + let mut set = Self::with_hasher_in(Default::default(), Default::default()); + set.extend(iter); + set + } +} + +// The default hasher is used to match the std implementation signature +#[cfg(feature = "ahash")] +impl From<[T; N]> for HashSet +where + T: Eq + Hash, + A: Default + Allocator, +{ + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let set1 = HashSet::from([1, 2, 3, 4]); + /// let set2: HashSet<_> = [1, 2, 3, 4].into(); + /// assert_eq!(set1, set2); + /// ``` + fn from(arr: [T; N]) -> Self { + arr.into_iter().collect() + } +} + +impl Extend for HashSet +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.map.extend(iter.into_iter().map(|k| (k, ()))); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: T) { + self.map.insert(k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl<'a, T, S, A> Extend<&'a T> for HashSet +where + T: 'a + Eq + Hash + Copy, + S: BuildHasher, + A: Allocator, +{ + #[cfg_attr(feature = "inline-more", inline)] + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().copied()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_one(&mut self, k: &'a T) { + self.map.insert(*k, ()); + } + + #[inline] + #[cfg(feature = "nightly")] + fn extend_reserve(&mut self, additional: usize) { + Extend::<(T, ())>::extend_reserve(&mut self.map, additional); + } +} + +impl Default for HashSet +where + S: Default, + A: Default + Allocator, +{ + /// Creates an empty `HashSet` with the `Default` value for the hasher. + #[cfg_attr(feature = "inline-more", inline)] + fn default() -> Self { + Self { + map: HashMap::default(), + } + } +} + +impl BitOr<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator, +{ + type Output = HashSet; + + /// Returns the union of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a | &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 3, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitor(self, rhs: &HashSet) -> HashSet { + self.union(rhs).cloned().collect() + } +} + +impl BitAnd<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, + A: Allocator, +{ + type Output = HashSet; + + /// Returns the intersection of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![2, 3, 4].into_iter().collect(); + /// + /// let set = &a & &b; + /// + /// let mut i = 0; + /// let expected = [2, 3]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitand(self, rhs: &HashSet) -> HashSet { + self.intersection(rhs).cloned().collect() + } +} + +impl BitXor<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a ^ &b; + /// + /// let mut i = 0; + /// let expected = [1, 2, 4, 5]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn bitxor(self, rhs: &HashSet) -> HashSet { + self.symmetric_difference(rhs).cloned().collect() + } +} + +impl Sub<&HashSet> for &HashSet +where + T: Eq + Hash + Clone, + S: BuildHasher + Default, +{ + type Output = HashSet; + + /// Returns the difference of `self` and `rhs` as a new `HashSet`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let a: HashSet<_> = vec![1, 2, 3].into_iter().collect(); + /// let b: HashSet<_> = vec![3, 4, 5].into_iter().collect(); + /// + /// let set = &a - &b; + /// + /// let mut i = 0; + /// let expected = [1, 2]; + /// for x in &set { + /// assert!(expected.contains(x)); + /// i += 1; + /// } + /// assert_eq!(i, expected.len()); + /// ``` + fn sub(self, rhs: &HashSet) -> HashSet { + self.difference(rhs).cloned().collect() + } +} + +/// An iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`iter`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`iter`]: struct.HashSet.html#method.iter +pub struct Iter<'a, K> { + iter: Keys<'a, K, ()>, +} + +/// An owning iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`into_iter`]: struct.HashSet.html#method.into_iter +pub struct IntoIter { + iter: map::IntoIter, +} + +/// A draining iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`drain`]: struct.HashSet.html#method.drain +pub struct Drain<'a, K, A: Allocator = Global> { + iter: map::Drain<'a, K, (), A>, +} + +/// A draining iterator over entries of a `HashSet` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by the [`extract_if`] method on [`HashSet`]. See its +/// documentation for more. +/// +/// [`extract_if`]: struct.HashSet.html#method.extract_if +/// [`HashSet`]: struct.HashSet.html +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, K, F, A: Allocator = Global> +where + F: FnMut(&K) -> bool, +{ + f: F, + inner: RawExtractIf<'a, (K, ()), A>, +} + +/// A lazy iterator producing elements in the intersection of `HashSet`s. +/// +/// This `struct` is created by the [`intersection`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`intersection`]: struct.HashSet.html#method.intersection +pub struct Intersection<'a, T, S, A: Allocator = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the difference of `HashSet`s. +/// +/// This `struct` is created by the [`difference`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`difference`]: struct.HashSet.html#method.difference +pub struct Difference<'a, T, S, A: Allocator = Global> { + // iterator of the first set + iter: Iter<'a, T>, + // the second set + other: &'a HashSet, +} + +/// A lazy iterator producing elements in the symmetric difference of `HashSet`s. +/// +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`HashSet`]. See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference +pub struct SymmetricDifference<'a, T, S, A: Allocator = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +/// A lazy iterator producing elements in the union of `HashSet`s. +/// +/// This `struct` is created by the [`union`] method on [`HashSet`]. +/// See its documentation for more. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`union`]: struct.HashSet.html#method.union +pub struct Union<'a, T, S, A: Allocator = Global> { + iter: Chain, Difference<'a, T, S, A>>, +} + +impl<'a, T, S, A: Allocator> IntoIterator for &'a HashSet { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl IntoIterator for HashSet { + type Item = T; + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec with a regular `.iter()`. + /// let v: Vec = set.into_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in &v { + /// println!("{}", x); + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + fn into_iter(self) -> IntoIter { + IntoIter { + iter: self.map.into_iter(), + } + } +} + +impl Clone for Iter<'_, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Iter { + iter: self.iter.clone(), + } + } +} +impl<'a, K> Iterator for Iter<'a, K> { + type Item = &'a K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a K> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} +impl<'a, K> ExactSizeIterator for Iter<'a, K> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Iter<'_, K> {} + +impl fmt::Debug for Iter<'_, K> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Iterator for IntoIter { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } +} +impl ExactSizeIterator for IntoIter { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for IntoIter {} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl Iterator for Drain<'_, K, A> { + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.iter.next() { + Some((k, _)) => Some(k), + None => None, + } + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, (k, ())| f(acc, k)) + } +} +impl ExactSizeIterator for Drain<'_, K, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn len(&self) -> usize { + self.iter.len() + } +} +impl FusedIterator for Drain<'_, K, A> {} + +impl fmt::Debug for Drain<'_, K, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let entries_iter = self.iter.iter().map(|(k, _)| k); + f.debug_list().entries(entries_iter).finish() + } +} + +impl Iterator for ExtractIf<'_, K, F, A> +where + F: FnMut(&K) -> bool, +{ + type Item = K; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option { + self.inner + .next(|&mut (ref k, ())| (self.f)(k)) + .map(|(k, ())| k) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, K, F, A> where F: FnMut(&K) -> bool {} + +impl Clone for Intersection<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Intersection { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Intersection<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + f(acc, elt) + } else { + acc + } + }) + } +} + +impl fmt::Debug for Intersection<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl FusedIterator for Intersection<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl Clone for Difference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Difference { + iter: self.iter.clone(), + ..*self + } + } +} + +impl<'a, T, S, A> Iterator for Difference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + loop { + let elt = self.iter.next()?; + if !self.other.contains(elt) { + return Some(elt); + } + } + } + + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, |acc, elt| { + if self.other.contains(elt) { + acc + } else { + f(acc, elt) + } + }) + } +} + +impl FusedIterator for Difference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for Difference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for SymmetricDifference<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + SymmetricDifference { + iter: self.iter.clone(), + } + } +} + +impl<'a, T, S, A> Iterator for SymmetricDifference<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +impl FusedIterator for SymmetricDifference<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for SymmetricDifference<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl Clone for Union<'_, T, S, A> { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Union { + iter: self.iter.clone(), + } + } +} + +impl FusedIterator for Union<'_, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ +} + +impl fmt::Debug for Union<'_, T, S, A> +where + T: fmt::Debug + Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.clone()).finish() + } +} + +impl<'a, T, S, A> Iterator for Union<'a, T, S, A> +where + T: Eq + Hash, + S: BuildHasher, + A: Allocator, +{ + type Item = &'a T; + + #[cfg_attr(feature = "inline-more", inline)] + fn next(&mut self) -> Option<&'a T> { + self.iter.next() + } + #[cfg_attr(feature = "inline-more", inline)] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + #[cfg_attr(feature = "inline-more", inline)] + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } +} + +/// A view into a single entry in a set, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashSet`]. +/// +/// [`HashSet`]: struct.HashSet.html +/// [`entry`]: struct.HashSet.html#method.entry +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// assert_eq!(set.len(), 3); +/// +/// // Existing value (insert) +/// let entry: Entry<_, _> = set.entry("a"); +/// let _raw_o: OccupiedEntry<_, _> = entry.insert(); +/// assert_eq!(set.len(), 3); +/// // Nonexistent value (insert) +/// set.entry("d").insert(); +/// +/// // Existing value (or_insert) +/// set.entry("b").or_insert(); +/// // Nonexistent value (or_insert) +/// set.entry("e").or_insert(); +/// +/// println!("Our HashSet: {:?}", set); +/// +/// let mut vec: Vec<_> = set.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// ``` +pub enum Entry<'a, T, S, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// let mut set: HashSet<_> = ["a", "b"].into(); + /// + /// match set.entry("a") { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => { } + /// } + /// ``` + Occupied(OccupiedEntry<'a, T, S, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// match set.entry("a") { + /// Entry::Occupied(_) => unreachable!(), + /// Entry::Vacant(_) => { } + /// } + /// ``` + Vacant(VacantEntry<'a, T, S, A>), +} + +impl fmt::Debug for Entry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, OccupiedEntry}; +/// +/// let mut set = HashSet::new(); +/// set.extend(["a", "b", "c"]); +/// +/// let _entry_o: OccupiedEntry<_, _> = set.entry("a").insert(); +/// assert_eq!(set.len(), 3); +/// +/// // Existing key +/// match set.entry("a") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(set.len(), 3); +/// +/// // Existing key (take) +/// match set.entry("c") { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove(), "c"); +/// } +/// } +/// assert_eq!(set.get(&"c"), None); +/// assert_eq!(set.len(), 2); +/// ``` +pub struct OccupiedEntry<'a, T, S, A: Allocator = Global> { + inner: map::OccupiedEntry<'a, T, (), S, A>, +} + +impl fmt::Debug for OccupiedEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashSet`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// use hashbrown::hash_set::{Entry, HashSet, VacantEntry}; +/// +/// let mut set = HashSet::<&str>::new(); +/// +/// let entry_v: VacantEntry<_, _> = match set.entry("a") { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert(); +/// assert!(set.contains("a") && set.len() == 1); +/// +/// // Nonexistent key (insert) +/// match set.entry("b") { +/// Entry::Vacant(view) => view.insert(), +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(set.contains("b") && set.len() == 2); +/// ``` +pub struct VacantEntry<'a, T, S, A: Allocator = Global> { + inner: map::VacantEntry<'a, T, (), S, A>, +} + +impl fmt::Debug for VacantEntry<'_, T, S, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.get()).finish() + } +} + +impl<'a, T, S, A: Allocator> Entry<'a, T, S, A> { + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// let entry = set.entry("horseyland").insert(); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert_entry(), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// // nonexistent key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// + /// // existing key + /// set.entry("poneyland").or_insert(); + /// assert!(set.contains("poneyland")); + /// assert_eq!(set.len(), 1); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn or_insert(self) + where + T: Hash, + S: BuildHasher, + { + if let Entry::Vacant(entry) = self { + entry.insert(); + } + } + + /// Returns a reference to this entry's value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// // existing key + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// // nonexistent key + /// assert_eq!(set.entry("horseland").get(), &"horseland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + match *self { + Entry::Occupied(ref entry) => entry.get(), + Entry::Vacant(ref entry) => entry.get(), + } + } +} + +impl OccupiedEntry<'_, T, S, A> { + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// set.entry("poneyland").or_insert(); + /// + /// match set.entry("poneyland") { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Takes the value out of the entry, and returns it. + /// Keeps the allocated memory for reuse. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// // The set is empty + /// assert!(set.is_empty() && set.capacity() == 0); + /// + /// set.entry("poneyland").or_insert(); + /// let capacity_before_remove = set.capacity(); + /// + /// if let Entry::Occupied(o) = set.entry("poneyland") { + /// assert_eq!(o.remove(), "poneyland"); + /// } + /// + /// assert_eq!(set.contains("poneyland"), false); + /// // Now set hold none elements but capacity is equal to the old one + /// assert!(set.len() == 0 && set.capacity() == capacity_before_remove); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> T { + self.inner.remove_entry().0 + } + + /// Replaces the entry, returning the old value. The new value in the hash map will be + /// the value used to create this entry. + /// + /// # Panics + /// + /// Will panic if this OccupiedEntry was created through [`Entry::insert`]. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// use std::rc::Rc; + /// + /// let mut set: HashSet> = HashSet::new(); + /// let key_one = Rc::new("Stringthing".to_string()); + /// let key_two = Rc::new("Stringthing".to_string()); + /// + /// set.insert(key_one.clone()); + /// assert!(Rc::strong_count(&key_one) == 2 && Rc::strong_count(&key_two) == 1); + /// + /// match set.entry(key_two.clone()) { + /// Entry::Occupied(entry) => { + /// let old_key: Rc = entry.replace(); + /// assert!(Rc::ptr_eq(&key_one, &old_key)); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert!(Rc::strong_count(&key_one) == 1 && Rc::strong_count(&key_two) == 2); + /// assert!(set.contains(&"Stringthing".to_owned())); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace(self) -> T { + self.inner.replace_key() + } +} + +impl<'a, T, S, A: Allocator> VacantEntry<'a, T, S, A> { + /// Gets a reference to the value that would be used when inserting + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// assert_eq!(set.entry("poneyland").get(), &"poneyland"); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn get(&self) -> &T { + self.inner.key() + } + + /// Take ownership of the value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_set::{Entry, HashSet}; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// match set.entry("poneyland") { + /// Entry::Occupied(_) => panic!(), + /// Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"), + /// } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn into_value(self) -> T { + self.inner.into_key() + } + + /// Sets the value of the entry with the VacantEntry's value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_set::Entry; + /// + /// let mut set: HashSet<&str> = HashSet::new(); + /// + /// if let Entry::Vacant(o) = set.entry("poneyland") { + /// o.insert(); + /// } + /// assert!(set.contains("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn insert(self) + where + T: Hash, + S: BuildHasher, + { + self.inner.insert(()); + } + + #[cfg_attr(feature = "inline-more", inline)] + fn insert_entry(self) -> OccupiedEntry<'a, T, S, A> + where + T: Hash, + S: BuildHasher, + { + OccupiedEntry { + inner: self.inner.insert_entry(()), + } + } +} + +#[allow(dead_code)] +fn assert_covariance() { + fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> { + v + } + fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { + v + } + fn into_iter<'new, A: Allocator>(v: IntoIter<&'static str, A>) -> IntoIter<&'new str, A> { + v + } + fn difference<'a, 'new, A: Allocator>( + v: Difference<'a, &'static str, DefaultHashBuilder, A>, + ) -> Difference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn symmetric_difference<'a, 'new, A: Allocator>( + v: SymmetricDifference<'a, &'static str, DefaultHashBuilder, A>, + ) -> SymmetricDifference<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn intersection<'a, 'new, A: Allocator>( + v: Intersection<'a, &'static str, DefaultHashBuilder, A>, + ) -> Intersection<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn union<'a, 'new, A: Allocator>( + v: Union<'a, &'static str, DefaultHashBuilder, A>, + ) -> Union<'a, &'new str, DefaultHashBuilder, A> { + v + } + fn drain<'new, A: Allocator>(d: Drain<'static, &'static str, A>) -> Drain<'new, &'new str, A> { + d + } +} + +#[cfg(test)] +mod test_set { + use super::super::map::DefaultHashBuilder; + use super::HashSet; + use std::vec::Vec; + + #[test] + fn test_zero_capacities() { + type HS = HashSet; + + let s = HS::new(); + assert_eq!(s.capacity(), 0); + + let s = HS::default(); + assert_eq!(s.capacity(), 0); + + let s = HS::with_hasher(DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity(0); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity_and_hasher(0, DefaultHashBuilder::default()); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.insert(1); + s.insert(2); + s.remove(&1); + s.remove(&2); + s.shrink_to_fit(); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.reserve(0); + assert_eq!(s.capacity(), 0); + } + + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.is_disjoint(&ys)); + assert!(!ys.is_disjoint(&xs)); + } + + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(!b.is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(b.is_superset(&a)); + } + + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let mut observed: u32 = 0; + for k in &a { + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); + } + + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let mut i = 0; + let expected = [1, 5, 11]; + for x in a.difference(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for x in a.symmetric_difference(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1; + } + assert_eq!(i, expected.len()); + } + + #[test] + fn test_from_map() { + let mut a = crate::HashMap::new(); + a.insert(1, ()); + a.insert(2, ()); + a.insert(3, ()); + a.insert(4, ()); + + let a: HashSet<_> = a.into(); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + } + + #[test] + fn test_from_iter() { + let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.iter().copied().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + + assert_eq!(set.iter().len(), xs.len() - 1); + } + + #[test] + fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); + } + + #[test] + fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(s1 != s2); + + s2.insert(3); + + assert_eq!(s1, s2); + } + + #[test] + fn test_show() { + let mut set = HashSet::new(); + let empty = HashSet::::new(); + + set.insert(1); + set.insert(2); + + let set_str = format!("{set:?}"); + + assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); + assert_eq!(format!("{empty:?}"), "{}"); + } + + #[test] + fn test_trivial_drain() { + let mut s = HashSet::::new(); + for _ in s.drain() {} + assert!(s.is_empty()); + drop(s); + + let mut s = HashSet::::new(); + drop(s.drain()); + assert!(s.is_empty()); + } + + #[test] + fn test_drain() { + let mut s: HashSet<_> = (1..100).collect(); + + // try this a bunch of times to make sure we don't screw up internal state. + for _ in 0..20 { + assert_eq!(s.len(), 99); + + { + let mut last_i = 0; + let mut d = s.drain(); + for (i, x) in d.by_ref().take(50).enumerate() { + last_i = i; + assert!(x != 0); + } + assert_eq!(last_i, 49); + } + + if !s.is_empty() { + panic!("s should be empty!"); + } + + // reset to try again. + s.extend(1..100); + } + } + + #[test] + fn test_replace() { + use core::hash; + + #[derive(Debug)] + #[allow(dead_code)] + struct Foo(&'static str, i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl Eq for Foo {} + + impl hash::Hash for Foo { + fn hash(&self, h: &mut H) { + self.0.hash(h); + } + } + + let mut s = HashSet::new(); + assert_eq!(s.replace(Foo("a", 1)), None); + assert_eq!(s.len(), 1); + assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); + assert_eq!(s.len(), 1); + + let mut it = s.iter(); + assert_eq!(it.next(), Some(&Foo("a", 2))); + assert_eq!(it.next(), None); + } + + #[test] + #[allow(clippy::needless_borrow)] + fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.extend([2, 3, 4]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); + } + + #[test] + fn test_retain() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut set: HashSet = xs.iter().copied().collect(); + set.retain(|&k| k % 2 == 0); + assert_eq!(set.len(), 3); + assert!(set.contains(&2)); + assert!(set.contains(&4)); + assert!(set.contains(&6)); + } + + #[test] + fn test_extract_if() { + { + let mut set: HashSet = (0..8).collect(); + let drained = set.extract_if(|&k| k % 2 == 0); + let mut out = drained.collect::>(); + out.sort_unstable(); + assert_eq!(vec![0, 2, 4, 6], out); + assert_eq!(set.len(), 4); + } + { + let mut set: HashSet = (0..8).collect(); + set.extract_if(|&k| k % 2 == 0).for_each(drop); + assert_eq!(set.len(), 4, "Removes non-matching items on drop"); + } + } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_SET: HashSet = HashSet::with_hasher(MyHasher); + + let mut set = EMPTY_SET; + set.insert(19); + assert!(set.contains(&19)); + } + + #[test] + fn rehash_in_place() { + let mut set = HashSet::new(); + + for i in 0..224 { + set.insert(i); + } + + assert_eq!( + set.capacity(), + 224, + "The set must be at or close to capacity to trigger a re hashing" + ); + + for i in 100..1400 { + set.remove(&(i - 100)); + set.insert(i); + } + } + + #[test] + fn collect() { + // At the time of writing, this hits the ZST case in from_base_index + // (and without the `map`, it does not). + let mut _set: HashSet<_> = (0..3).map(|_| ()).collect(); + } +} diff --git a/third_party/crates/hashbrown-0.14.5/src/table.rs b/third_party/crates/hashbrown-0.14.5/src/table.rs new file mode 100644 index 0000000..faf8a63 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/src/table.rs @@ -0,0 +1,2070 @@ +use core::{fmt, iter::FusedIterator, marker::PhantomData}; + +use crate::{ + raw::{ + Allocator, Bucket, Global, InsertSlot, RawDrain, RawExtractIf, RawIntoIter, RawIter, + RawTable, + }, + TryReserveError, +}; + +/// Low-level hash table with explicit hashing. +/// +/// The primary use case for this type over [`HashMap`] or [`HashSet`] is to +/// support types that do not implement the [`Hash`] and [`Eq`] traits, but +/// instead require additional data not contained in the key itself to compute a +/// hash and compare two elements for equality. +/// +/// Examples of when this can be useful include: +/// - An `IndexMap` implementation where indices into a `Vec` are stored as +/// elements in a `HashTable`. Hashing and comparing the elements +/// requires indexing the associated `Vec` to get the actual value referred to +/// by the index. +/// - Avoiding re-computing a hash when it is already known. +/// - Mutating the key of an element in a way that doesn't affect its hash. +/// +/// To achieve this, `HashTable` methods that search for an element in the table +/// require a hash value and equality function to be explicitly passed in as +/// arguments. The method will then iterate over the elements with the given +/// hash and call the equality function on each of them, until a match is found. +/// +/// In most cases, a `HashTable` will not be exposed directly in an API. It will +/// instead be wrapped in a helper type which handles the work of calculating +/// hash values and comparing elements. +/// +/// Due to its low-level nature, this type provides fewer guarantees than +/// [`HashMap`] and [`HashSet`]. Specifically, the API allows you to shoot +/// yourself in the foot by having multiple elements with identical keys in the +/// table. The table itself will still function correctly and lookups will +/// arbitrarily return one of the matching elements. However you should avoid +/// doing this because it changes the runtime of hash table operations from +/// `O(1)` to `O(k)` where `k` is the number of duplicate entries. +/// +/// [`HashMap`]: super::HashMap +/// [`HashSet`]: super::HashSet +pub struct HashTable +where + A: Allocator, +{ + pub(crate) raw: RawTable, +} + +impl HashTable { + /// Creates an empty `HashTable`. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::new(); + /// assert_eq!(table.len(), 0); + /// assert_eq!(table.capacity(), 0); + /// ``` + pub const fn new() -> Self { + Self { + raw: RawTable::new(), + } + } + + /// Creates an empty `HashTable` with the specified capacity. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let mut table: HashTable<&str> = HashTable::with_capacity(10); + /// assert_eq!(table.len(), 0); + /// assert!(table.capacity() >= 10); + /// ``` + pub fn with_capacity(capacity: usize) -> Self { + Self { + raw: RawTable::with_capacity(capacity), + } + } +} + +impl HashTable +where + A: Allocator, +{ + /// Creates an empty `HashTable` using the given allocator. + /// + /// The hash table is initially created with a capacity of 0, so it will not allocate until it + /// is first inserted into. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use bumpalo::Bump; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::new_in(&bump); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// + /// // The created HashTable also doesn't allocate memory + /// assert_eq!(table.capacity(), 0); + /// + /// // Now we insert element inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// // We can see that the HashTable holds 1 element + /// assert_eq!(table.len(), 1); + /// // And it also allocates some capacity + /// assert!(table.capacity() > 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub const fn new_in(alloc: A) -> Self { + Self { + raw: RawTable::new_in(alloc), + } + } + + /// Creates an empty `HashTable` with the specified capacity using the given allocator. + /// + /// The hash table will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash table will not allocate. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use bumpalo::Bump; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let bump = Bump::new(); + /// let mut table = HashTable::with_capacity_in(5, &bump); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // The created HashTable holds none elements + /// assert_eq!(table.len(), 0); + /// // But it can hold at least 5 elements without reallocating + /// let empty_map_capacity = table.capacity(); + /// assert!(empty_map_capacity >= 5); + /// + /// // Now we insert some 5 elements inside created HashTable + /// table.insert_unique(hasher(&"One"), "One", hasher); + /// table.insert_unique(hasher(&"Two"), "Two", hasher); + /// table.insert_unique(hasher(&"Three"), "Three", hasher); + /// table.insert_unique(hasher(&"Four"), "Four", hasher); + /// table.insert_unique(hasher(&"Five"), "Five", hasher); + /// + /// // We can see that the HashTable holds 5 elements + /// assert_eq!(table.len(), 5); + /// // But its capacity isn't changed + /// assert_eq!(table.capacity(), empty_map_capacity) + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self { + raw: RawTable::with_capacity_in(capacity, alloc), + } + } + + /// Returns a reference to the underlying allocator. + pub fn allocator(&self) -> &A { + self.raw.allocator() + } + + /// Returns a reference to an entry in the table with the given hash and + /// which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// assert_eq!(table.find(hasher(&2), |&val| val == 2), Some(&2)); + /// assert_eq!(table.find(hasher(&4), |&val| val == 4), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find(&self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&T> { + self.raw.get(hash, eq) + } + + /// Returns a mutable reference to an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// When mutating an entry, you should ensure that it still retains the same + /// hash value as when it was inserted, otherwise lookups of that entry may + /// fail to find it. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Some(val) = table.find_mut(hasher(&1), |val| val.0 == 1) { + /// val.1 = "b"; + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), Some(&(1, "b"))); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn find_mut(&mut self, hash: u64, eq: impl FnMut(&T) -> bool) -> Option<&mut T> { + self.raw.get_mut(hash, eq) + } + + /// Returns an `OccupiedEntry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table. Call + /// [`HashTable::entry`] instead if you wish to insert an entry if the + /// lookup fails. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Ok(entry) = table.find_entry(hasher(&1), |val| val.0 == 1) { + /// entry.remove(); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn find_entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + ) -> Result, AbsentEntry<'_, T, A>> { + match self.raw.find(hash, eq) { + Some(bucket) => Ok(OccupiedEntry { + hash, + bucket, + table: self, + }), + None => Err(AbsentEntry { table: self }), + } + } + + /// Returns an `Entry` for an entry in the table with the given hash + /// and which satisfies the equality function passed. + /// + /// This can be used to remove the entry from the table, or insert a new + /// entry with the given hash if one doesn't already exist. + /// + /// This method will call `eq` for all entries with the given hash, but may + /// also call it for entries with a different hash. `eq` should only return + /// true for the desired entry, at which point the search is stopped. + /// + /// This method may grow the table in preparation for an insertion. Call + /// [`HashTable::find_entry`] if this is undesirable. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), (1, "a"), |val| hasher(&val.0)); + /// if let Entry::Occupied(entry) = table.entry(hasher(&1), |val| val.0 == 1, |val| hasher(&val.0)) + /// { + /// entry.remove(); + /// } + /// if let Entry::Vacant(entry) = table.entry(hasher(&2), |val| val.0 == 2, |val| hasher(&val.0)) { + /// entry.insert((2, "b")); + /// } + /// assert_eq!(table.find(hasher(&1), |val| val.0 == 1), None); + /// assert_eq!(table.find(hasher(&2), |val| val.0 == 2), Some(&(2, "b"))); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn entry( + &mut self, + hash: u64, + eq: impl FnMut(&T) -> bool, + hasher: impl Fn(&T) -> u64, + ) -> Entry<'_, T, A> { + match self.raw.find_or_find_insert_slot(hash, eq, hasher) { + Ok(bucket) => Entry::Occupied(OccupiedEntry { + hash, + bucket, + table: self, + }), + Err(insert_slot) => Entry::Vacant(VacantEntry { + hash, + insert_slot, + table: self, + }), + } + } + + /// Inserts an element into the `HashTable` with the given hash value, but + /// without checking whether an equivalent element already exists within the + /// table. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut v = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert_unique( + &mut self, + hash: u64, + value: T, + hasher: impl Fn(&T) -> u64, + ) -> OccupiedEntry<'_, T, A> { + let bucket = self.raw.insert(hash, value, hasher); + OccupiedEntry { + hash, + bucket, + table: self, + } + } + + /// Clears the table, removing all values. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut v = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// v.insert_unique(hasher(&1), 1, hasher); + /// v.clear(); + /// assert!(v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn clear(&mut self) { + self.raw.clear(); + } + + /// Shrinks the capacity of the table as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to_fit(hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to_fit(&mut self, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(self.len(), hasher) + } + + /// Shrinks the capacity of the table with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::with_capacity(100); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// assert!(table.capacity() >= 100); + /// table.shrink_to(10, hasher); + /// assert!(table.capacity() >= 10); + /// table.shrink_to(0, hasher); + /// assert!(table.capacity() >= 2); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn shrink_to(&mut self, min_capacity: usize, hasher: impl Fn(&T) -> u64) { + self.raw.shrink_to(min_capacity, hasher); + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Panics + /// + /// Panics if the new capacity exceeds [`isize::MAX`] bytes and [`abort`] the program + /// in case of allocation error. Use [`try_reserve`](HashTable::try_reserve) instead + /// if you want to handle memory allocation failure. + /// + /// [`isize::MAX`]: https://doc.rust-lang.org/std/primitive.isize.html + /// [`abort`]: https://doc.rust-lang.org/alloc/alloc/fn.handle_alloc_error.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.reserve(10, hasher); + /// assert!(table.capacity() >= 10); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { + self.raw.reserve(additional, hasher) + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashTable`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// `hasher` is called if entries need to be moved or copied to a new table. + /// This must return the same hash value that each entry was inserted with. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table + /// .try_reserve(10, hasher) + /// .expect("why is the test harness OOMing on 10 bytes?"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn try_reserve( + &mut self, + additional: usize, + hasher: impl Fn(&T) -> u64, + ) -> Result<(), TryReserveError> { + self.raw.try_reserve(additional, hasher) + } + + /// Returns the number of elements the table can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashTable; + /// let table: HashTable = HashTable::with_capacity(100); + /// assert!(table.capacity() >= 100); + /// ``` + pub fn capacity(&self) -> usize { + self.raw.capacity() + } + + /// Returns the number of elements in the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert_eq!(v.len(), 0); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert_eq!(v.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn len(&self) -> usize { + self.raw.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// let mut v = HashTable::new(); + /// assert!(v.is_empty()); + /// v.insert_unique(hasher(&1), 1, hasher); + /// assert!(!v.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn is_empty(&self) -> bool { + self.raw.is_empty() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"a"), "b", hasher); + /// table.insert_unique(hasher(&"b"), "b", hasher); + /// + /// // Will print in an arbitrary order. + /// for x in table.iter() { + /// println!("{}", x); + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter(&self) -> Iter<'_, T> { + Iter { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// An iterator visiting all elements in arbitrary order, + /// with mutable references to the elements. + /// The iterator element type is `&'a mut T`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&1), 1, hasher); + /// table.insert_unique(hasher(&2), 2, hasher); + /// table.insert_unique(hasher(&3), 3, hasher); + /// + /// // Update all values + /// for val in table.iter_mut() { + /// *val *= 2; + /// } + /// + /// assert_eq!(table.len(), 3); + /// let mut vec: Vec = Vec::new(); + /// + /// for val in &table { + /// println!("val: {}", val); + /// vec.push(*val); + /// } + /// + /// // The `Iter` iterator produces items in arbitrary order, so the + /// // items must be sorted to test them against a sorted array. + /// vec.sort_unstable(); + /// assert_eq!(vec, [2, 4, 6]); + /// + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut { + inner: unsafe { self.raw.iter() }, + marker: PhantomData, + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=6 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// table.retain(|&mut x| x % 2 == 0); + /// assert_eq!(table.len(), 3); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn retain(&mut self, mut f: impl FnMut(&mut T) -> bool) { + // Here we only use `iter` as a temporary, preventing use-after-free + unsafe { + for item in self.raw.iter() { + if !f(item.as_mut()) { + self.raw.erase(item); + } + } + } + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 1..=3 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// assert!(!table.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in table.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(table.is_empty()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn drain(&mut self) -> Drain<'_, T, A> { + Drain { + inner: self.raw.drain(), + } + } + + /// Drains elements which are true under the given predicate, + /// and returns an iterator over the removed items. + /// + /// In other words, move all elements `e` such that `f(&e)` returns `true` out + /// into another iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use [`retain()`] with a negated predicate if you do not need the returned iterator. + /// + /// [`retain()`]: HashTable::retain + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in 0..8 { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// let drained: Vec = table.extract_if(|&mut v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = table.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&mut T) -> bool, + { + ExtractIf { + f, + inner: RawExtractIf { + iter: unsafe { self.raw.iter() }, + table: &mut self.raw, + }, + } + } + + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be returned if any of the + /// keys are duplicates or missing. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// Some([&mut ("Athenæum", 1807), &mut ("Library of Congress", 1800),]), + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let keys = ["Athenæum", "Athenæum"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn get_many_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + self.raw.get_many_mut(hashes, eq) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// The `eq` argument should be a closure such that `eq(i, k)` returns true if `k` is equal to + /// the `i`th key to be looked up. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_mut`](`HashTable::get_many_mut`). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut libraries: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for (k, v) in [ + /// ("Bodleian Library", 1602), + /// ("Athenæum", 1807), + /// ("Herzogin-Anna-Amalia-Bibliothek", 1691), + /// ("Library of Congress", 1800), + /// ] { + /// libraries.insert_unique(hasher(&k), (k, v), |(k, _)| hasher(&k)); + /// } + /// + /// let keys = ["Athenæum", "Library of Congress"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!( + /// got, + /// Some([&mut ("Athenæum", 1807), &mut ("Library of Congress", 1800),]), + /// ); + /// + /// // Missing keys result in None + /// let keys = ["Athenæum", "New York Public Library"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let keys = ["Athenæum", "Athenæum"]; + /// let got = libraries.get_many_mut(keys.map(|k| hasher(&k)), |i, val| keys[i] == val.0); + /// assert_eq!(got, None); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub unsafe fn get_many_unchecked_mut( + &mut self, + hashes: [u64; N], + eq: impl FnMut(usize, &T) -> bool, + ) -> Option<[&'_ mut T; N]> { + self.raw.get_many_unchecked_mut(hashes, eq) + } +} + +impl IntoIterator for HashTable +where + A: Allocator, +{ + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { + inner: self.raw.into_iter(), + } + } +} + +impl<'a, T, A> IntoIterator for &'a HashTable +where + A: Allocator, +{ + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T, A> IntoIterator for &'a mut HashTable +where + A: Allocator, +{ + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +impl Default for HashTable +where + A: Allocator + Default, +{ + fn default() -> Self { + Self { + raw: Default::default(), + } + } +} + +impl Clone for HashTable +where + T: Clone, + A: Allocator + Clone, +{ + fn clone(&self) -> Self { + Self { + raw: self.raw.clone(), + } + } +} + +impl fmt::Debug for HashTable +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_set().entries(self.iter()).finish() + } +} + +/// A view into a single entry in a table, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashTable`]. +/// +/// [`HashTable`]: struct.HashTable.html +/// [`entry`]: struct.HashTable.html#method.entry +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// // Existing value (insert) +/// let entry: Entry<_> = table.entry(hasher(&"a"), |&x| x == "a", hasher); +/// let _raw_o: OccupiedEntry<_, _> = entry.insert("a"); +/// assert_eq!(table.len(), 3); +/// // Nonexistent value (insert) +/// table.entry(hasher(&"d"), |&x| x == "d", hasher).insert("d"); +/// +/// // Existing value (or_insert) +/// table +/// .entry(hasher(&"b"), |&x| x == "b", hasher) +/// .or_insert("b"); +/// // Nonexistent value (or_insert) +/// table +/// .entry(hasher(&"e"), |&x| x == "e", hasher) +/// .or_insert("e"); +/// +/// println!("Our HashTable: {:?}", table); +/// +/// let mut vec: Vec<_> = table.iter().copied().collect(); +/// // The `Iter` iterator produces items in arbitrary order, so the +/// // items must be sorted to test them against a sorted array. +/// vec.sort_unstable(); +/// assert_eq!(vec, ["a", "b", "c", "d", "e"]); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub enum Entry<'a, T, A = Global> +where + A: Allocator, +{ + /// An occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// for x in ["a", "b"] { + /// table.insert_unique(hasher(&x), x, hasher); + /// } + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => unreachable!(), + /// Entry::Occupied(_) => {} + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Occupied(OccupiedEntry<'a, T, A>), + + /// A vacant entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table = HashTable::<&str>::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { + /// Entry::Vacant(_) => {} + /// Entry::Occupied(_) => unreachable!(), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + Vacant(VacantEntry<'a, T, A>), +} + +impl fmt::Debug for Entry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +impl<'a, T, A> Entry<'a, T, A> +where + A: Allocator, +{ + /// Sets the value of the entry, replacing any existing value if there is + /// one, and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// let entry = table + /// .entry(hasher(&"horseyland"), |&x| x == "horseyland", hasher) + /// .insert("horseyland"); + /// + /// assert_eq!(entry.get(), &"horseyland"); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(mut entry) => { + *entry.get_mut() = value; + entry + } + Entry::Vacant(entry) => entry.insert(value), + } + } + + /// Ensures a value is in the entry by inserting if it was vacant. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// // nonexistent key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// + /// // existing key + /// table + /// .entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) + /// .or_insert("poneyland"); + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_some()); + /// assert_eq!(table.len(), 1); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert(self, default: T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty.. + /// + /// Returns an [`OccupiedEntry`] pointing to the now-occupied entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry(hasher("poneyland"), |x| x == "poneyland", |val| hasher(val)) + /// .or_insert_with(|| "poneyland".to_string()); + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |x| x == "poneyland") + /// .is_some()); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn or_insert_with(self, default: impl FnOnce() -> T) -> OccupiedEntry<'a, T, A> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(entry) => entry.insert(default()), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the table. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 42)) + /// ); + /// + /// table + /// .entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) + /// .and_modify(|(_, v)| *v += 1) + /// .or_insert(("poneyland", 42)); + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(k, _)| k == "poneyland"), + /// Some(&("poneyland", 43)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn and_modify(self, f: impl FnOnce(&mut T)) -> Self { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } +} + +/// A view into an occupied entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{Entry, HashTable, OccupiedEntry}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// for x in ["a", "b", "c"] { +/// table.insert_unique(hasher(&x), x, hasher); +/// } +/// assert_eq!(table.len(), 3); +/// +/// let _entry_o: OccupiedEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap(); +/// assert_eq!(table.len(), 3); +/// +/// // Existing key +/// match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.get(), &"a"); +/// } +/// } +/// +/// assert_eq!(table.len(), 3); +/// +/// // Existing key (take) +/// match table.entry(hasher(&"c"), |&x| x == "c", hasher) { +/// Entry::Vacant(_) => unreachable!(), +/// Entry::Occupied(view) => { +/// assert_eq!(view.remove().0, "c"); +/// } +/// } +/// assert_eq!(table.find(hasher(&"c"), |&x| x == "c"), None); +/// assert_eq!(table.len(), 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct OccupiedEntry<'a, T, A = Global> +where + A: Allocator, +{ + hash: u64, + bucket: Bucket, + table: &'a mut HashTable, +} + +unsafe impl Send for OccupiedEntry<'_, T, A> +where + T: Send, + A: Send + Allocator, +{ +} +unsafe impl Sync for OccupiedEntry<'_, T, A> +where + T: Sync, + A: Sync + Allocator, +{ +} + +impl fmt::Debug for OccupiedEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("value", self.get()) + .finish() + } +} + +impl<'a, T, A> OccupiedEntry<'a, T, A> +where + A: Allocator, +{ + /// Takes the value out of the entry, and returns it along with a + /// `VacantEntry` that can be used to insert another value with the same + /// hash as the one that was just removed. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// // The table is empty + /// assert!(table.is_empty() && table.capacity() == 0); + /// + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// let capacity_before_remove = table.capacity(); + /// + /// if let Entry::Occupied(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// assert_eq!(o.remove().0, "poneyland"); + /// } + /// + /// assert!(table + /// .find(hasher(&"poneyland"), |&x| x == "poneyland") + /// .is_none()); + /// // Now table hold none elements but capacity is equal to the old one + /// assert!(table.len() == 0 && table.capacity() == capacity_before_remove); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn remove(self) -> (T, VacantEntry<'a, T, A>) { + let (val, slot) = unsafe { self.table.raw.remove(self.bucket) }; + ( + val, + VacantEntry { + hash: self.hash, + insert_slot: slot, + table: self.table, + }, + ) + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), "poneyland", hasher); + /// + /// match table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// Entry::Vacant(_) => panic!(), + /// Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"), + /// } + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get(&self) -> &T { + unsafe { self.bucket.as_ref() } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// if let Entry::Occupied(mut o) = table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// o.get_mut().1 += 10; + /// assert_eq!(o.get().1, 22); + /// + /// // We can use the same Entry multiple times. + /// o.get_mut().1 += 2; + /// } + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 24)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the table itself. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<(&str, u32)> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// table.insert_unique(hasher(&"poneyland"), ("poneyland", 12), |(k, _)| hasher(&k)); + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 12)) + /// ); + /// + /// let value: &mut (&str, u32); + /// match table.entry( + /// hasher(&"poneyland"), + /// |&(x, _)| x == "poneyland", + /// |(k, _)| hasher(&k), + /// ) { + /// Entry::Occupied(entry) => value = entry.into_mut(), + /// Entry::Vacant(_) => panic!(), + /// } + /// value.1 += 10; + /// + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&(x, _)| x == "poneyland",), + /// Some(&("poneyland", 22)) + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + pub fn into_mut(self) -> &'a mut T { + unsafe { self.bucket.as_mut() } + } + + /// Converts the OccupiedEntry into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// A view into a vacant entry in a `HashTable`. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{Entry, HashTable, VacantEntry}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: VacantEntry<_, _> = match table.entry(hasher(&"a"), |&x| x == "a", hasher) { +/// Entry::Vacant(view) => view, +/// Entry::Occupied(_) => unreachable!(), +/// }; +/// entry_v.insert("a"); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct VacantEntry<'a, T, A = Global> +where + A: Allocator, +{ + hash: u64, + insert_slot: InsertSlot, + table: &'a mut HashTable, +} + +impl fmt::Debug for VacantEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("VacantEntry") + } +} + +impl<'a, T, A> VacantEntry<'a, T, A> +where + A: Allocator, +{ + /// Inserts a new element into the table with the hash that was used to + /// obtain the `VacantEntry`. + /// + /// An `OccupiedEntry` is returned for the newly inserted element. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(feature = "nightly")] + /// # fn test() { + /// use ahash::AHasher; + /// use hashbrown::hash_table::Entry; + /// use hashbrown::HashTable; + /// use std::hash::{BuildHasher, BuildHasherDefault}; + /// + /// let mut table: HashTable<&str> = HashTable::new(); + /// let hasher = BuildHasherDefault::::default(); + /// let hasher = |val: &_| hasher.hash_one(val); + /// + /// if let Entry::Vacant(o) = table.entry(hasher(&"poneyland"), |&x| x == "poneyland", hasher) { + /// o.insert("poneyland"); + /// } + /// assert_eq!( + /// table.find(hasher(&"poneyland"), |&x| x == "poneyland"), + /// Some(&"poneyland") + /// ); + /// # } + /// # fn main() { + /// # #[cfg(feature = "nightly")] + /// # test() + /// # } + /// ``` + #[inline] + pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> { + let bucket = unsafe { + self.table + .raw + .insert_in_slot(self.hash, self.insert_slot, value) + }; + OccupiedEntry { + hash: self.hash, + bucket, + table: self.table, + } + } + + /// Converts the VacantEntry into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// Type representing the absence of an entry, as returned by [`HashTable::find_entry`]. +/// +/// This type only exists due to [limitations] in Rust's NLL borrow checker. In +/// the future, `find_entry` will return an `Option` and this +/// type will be removed. +/// +/// [limitations]: https://smallcultfollowing.com/babysteps/blog/2018/06/15/mir-based-borrow-check-nll-status-update/#polonius +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "nightly")] +/// # fn test() { +/// use ahash::AHasher; +/// use hashbrown::hash_table::{AbsentEntry, Entry, HashTable}; +/// use std::hash::{BuildHasher, BuildHasherDefault}; +/// +/// let mut table: HashTable<&str> = HashTable::new(); +/// let hasher = BuildHasherDefault::::default(); +/// let hasher = |val: &_| hasher.hash_one(val); +/// +/// let entry_v: AbsentEntry<_, _> = table.find_entry(hasher(&"a"), |&x| x == "a").unwrap_err(); +/// entry_v +/// .into_table() +/// .insert_unique(hasher(&"a"), "a", hasher); +/// assert!(table.find(hasher(&"a"), |&x| x == "a").is_some() && table.len() == 1); +/// +/// // Nonexistent key (insert) +/// match table.entry(hasher(&"b"), |&x| x == "b", hasher) { +/// Entry::Vacant(view) => { +/// view.insert("b"); +/// } +/// Entry::Occupied(_) => unreachable!(), +/// } +/// assert!(table.find(hasher(&"b"), |&x| x == "b").is_some() && table.len() == 2); +/// # } +/// # fn main() { +/// # #[cfg(feature = "nightly")] +/// # test() +/// # } +/// ``` +pub struct AbsentEntry<'a, T, A = Global> +where + A: Allocator, +{ + table: &'a mut HashTable, +} + +impl fmt::Debug for AbsentEntry<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("AbsentEntry") + } +} + +impl<'a, T, A> AbsentEntry<'a, T, A> +where + A: Allocator, +{ + /// Converts the AbsentEntry into a mutable reference to the underlying + /// table. + pub fn into_table(self) -> &'a mut HashTable { + self.table + } +} + +/// An iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a T`. +/// +/// This `struct` is created by the [`iter`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.HashTable.html#method.iter +/// [`HashTable`]: struct.HashTable.html +pub struct Iter<'a, T> { + inner: RawIter, + marker: PhantomData<&'a T>, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_ref() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_ref()) }) + } +} + +impl ExactSizeIterator for Iter<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for Iter<'_, T> {} + +/// A mutable iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `&'a mut T`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`HashTable`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.HashTable.html#method.iter_mut +/// [`HashTable`]: struct.HashTable.html +pub struct IterMut<'a, T> { + inner: RawIter, + marker: PhantomData<&'a mut T>, +} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + // Avoid `Option::map` because it bloats LLVM IR. + match self.inner.next() { + Some(bucket) => Some(unsafe { bucket.as_mut() }), + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner + .fold(init, |acc, bucket| unsafe { f(acc, bucket.as_mut()) }) + } +} + +impl ExactSizeIterator for IterMut<'_, T> { + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IterMut<'_, T> {} + +/// An owning iterator over the entries of a `HashTable` in arbitrary order. +/// The iterator element type is `T`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashTable`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// The table cannot be used after calling that method. +/// +/// [`into_iter`]: struct.HashTable.html#method.into_iter +/// [`HashTable`]: struct.HashTable.html +/// [`IntoIterator`]: https://doc.rust-lang.org/core/iter/trait.IntoIterator.html +pub struct IntoIter +where + A: Allocator, +{ + inner: RawIntoIter, +} + +impl Iterator for IntoIter +where + A: Allocator, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn fold(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } +} + +impl ExactSizeIterator for IntoIter +where + A: Allocator, +{ + fn len(&self) -> usize { + self.inner.len() + } +} + +impl FusedIterator for IntoIter where A: Allocator {} + +/// A draining iterator over the items of a `HashTable`. +/// +/// This `struct` is created by the [`drain`] method on [`HashTable`]. +/// See its documentation for more. +/// +/// [`HashTable`]: struct.HashTable.html +/// [`drain`]: struct.HashTable.html#method.drain +pub struct Drain<'a, T, A: Allocator = Global> { + inner: RawDrain<'a, T, A>, +} + +impl Drain<'_, T, A> { + /// Returns a iterator of references over the remaining items. + fn iter(&self) -> Iter<'_, T> { + Iter { + inner: self.inner.iter(), + marker: PhantomData, + } + } +} + +impl Iterator for Drain<'_, T, A> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.next() + } + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +impl ExactSizeIterator for Drain<'_, T, A> { + fn len(&self) -> usize { + self.inner.len() + } +} +impl FusedIterator for Drain<'_, T, A> {} + +impl fmt::Debug for Drain<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +/// A draining iterator over entries of a `HashTable` which don't satisfy the predicate `f`. +/// +/// This `struct` is created by [`HashTable::extract_if`]. See its +/// documentation for more. +#[must_use = "Iterators are lazy unless consumed"] +pub struct ExtractIf<'a, T, F, A: Allocator = Global> +where + F: FnMut(&mut T) -> bool, +{ + f: F, + inner: RawExtractIf<'a, T, A>, +} + +impl Iterator for ExtractIf<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next(|val| (self.f)(val)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } +} + +impl FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool {} diff --git a/third_party/crates/hashbrown-0.14.5/tests/equivalent_trait.rs b/third_party/crates/hashbrown-0.14.5/tests/equivalent_trait.rs new file mode 100644 index 0000000..713dddd --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/tests/equivalent_trait.rs @@ -0,0 +1,53 @@ +use hashbrown::Equivalent; +use hashbrown::HashMap; + +use std::hash::Hash; + +#[derive(Debug, Hash)] +pub struct Pair(pub A, pub B); + +impl PartialEq<(A, B)> for Pair +where + C: PartialEq, + D: PartialEq, +{ + fn eq(&self, rhs: &(A, B)) -> bool { + self.0 == rhs.0 && self.1 == rhs.1 + } +} + +impl Equivalent for Pair +where + Pair: PartialEq, + A: Hash + Eq, + B: Hash + Eq, +{ + fn equivalent(&self, other: &X) -> bool { + *self == *other + } +} + +#[test] +fn test_lookup() { + let s = String::from; + let mut map = HashMap::new(); + map.insert((s("a"), s("b")), 1); + map.insert((s("a"), s("x")), 2); + + assert!(map.contains_key(&Pair("a", "b"))); + assert!(!map.contains_key(&Pair("b", "a"))); +} + +#[test] +fn test_string_str() { + let s = String::from; + let mut map = HashMap::new(); + map.insert(s("a"), 1); + map.insert(s("b"), 2); + map.insert(s("x"), 3); + map.insert(s("y"), 4); + + assert!(map.contains_key("a")); + assert!(!map.contains_key("z")); + assert_eq!(map.remove("b"), Some(2)); +} diff --git a/third_party/crates/hashbrown-0.14.5/tests/hasher.rs b/third_party/crates/hashbrown-0.14.5/tests/hasher.rs new file mode 100644 index 0000000..e455e3d --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/tests/hasher.rs @@ -0,0 +1,65 @@ +//! Sanity check that alternate hashers work correctly. + +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use std::hash::{BuildHasher, BuildHasherDefault, Hasher}; + +fn check() { + let range = 0..1_000; + + let mut set = HashSet::::default(); + set.extend(range.clone()); + + assert!(!set.contains(&i32::min_value())); + assert!(!set.contains(&(range.start - 1))); + for i in range.clone() { + assert!(set.contains(&i)); + } + assert!(!set.contains(&range.end)); + assert!(!set.contains(&i32::max_value())); +} + +/// Use hashbrown's default hasher. +#[test] +fn default() { + check::(); +} + +/// Use std's default hasher. +#[test] +fn random_state() { + check::(); +} + +/// Use a constant 0 hash. +#[test] +fn zero() { + #[derive(Default)] + struct ZeroHasher; + + impl Hasher for ZeroHasher { + fn finish(&self) -> u64 { + 0 + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} + +/// Use a constant maximum hash. +#[test] +fn max() { + #[derive(Default)] + struct MaxHasher; + + impl Hasher for MaxHasher { + fn finish(&self) -> u64 { + u64::max_value() + } + fn write(&mut self, _: &[u8]) {} + } + + check::>(); +} diff --git a/third_party/crates/hashbrown-0.14.5/tests/raw.rs b/third_party/crates/hashbrown-0.14.5/tests/raw.rs new file mode 100644 index 0000000..858836e --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/tests/raw.rs @@ -0,0 +1,11 @@ +#![cfg(feature = "raw")] + +use hashbrown::raw::RawTable; +use std::mem; + +#[test] +fn test_allocation_info() { + assert_eq!(RawTable::<()>::new().allocation_info().1.size(), 0); + assert_eq!(RawTable::::new().allocation_info().1.size(), 0); + assert!(RawTable::::with_capacity(1).allocation_info().1.size() > mem::size_of::()); +} diff --git a/third_party/crates/hashbrown-0.14.5/tests/rayon.rs b/third_party/crates/hashbrown-0.14.5/tests/rayon.rs new file mode 100644 index 0000000..d55e5a9 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/tests/rayon.rs @@ -0,0 +1,535 @@ +#![cfg(feature = "rayon")] + +#[macro_use] +extern crate lazy_static; + +use hashbrown::{HashMap, HashSet}; +use rayon::iter::{ + IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelExtend, + ParallelIterator, +}; + +macro_rules! assert_eq3 { + ($e1:expr, $e2:expr, $e3:expr) => {{ + assert_eq!($e1, $e2); + assert_eq!($e1, $e3); + assert_eq!($e2, $e3); + }}; +} + +lazy_static! { + static ref MAP_EMPTY: HashMap = HashMap::new(); + static ref MAP: HashMap = { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m.insert('c', 30); + m.insert('e', 50); + m.insert('f', 60); + m.insert('d', 40); + m + }; +} + +#[test] +fn map_seq_par_equivalence_iter_empty() { + let vec_seq = MAP_EMPTY.iter().collect::>(); + let vec_par = MAP_EMPTY.par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter() { + let mut vec_seq = MAP.iter().collect::>(); + let mut vec_par = MAP.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &10), + (&'b', &20), + (&'c', &30), + (&'d', &40), + (&'e', &50), + (&'f', &60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_keys_empty() { + let vec_seq = MAP_EMPTY.keys().collect::>(); + let vec_par = MAP_EMPTY.par_keys().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_keys() { + let mut vec_seq = MAP.keys().collect::>(); + let mut vec_par = MAP.par_keys().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_empty() { + let vec_seq = MAP_EMPTY.values().collect::>(); + let vec_par = MAP_EMPTY.par_values().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values() { + let mut vec_seq = MAP.values().collect::>(); + let mut vec_par = MAP.par_values().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&10, &20, &30, &40, &50, &60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_iter_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.iter_mut().collect::>(); + let vec_par = map2.par_iter_mut().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_iter_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.iter_mut().collect::>(); + let mut vec_par = map2.par_iter_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + (&'a', &mut 10), + (&'b', &mut 20), + (&'c', &mut 30), + (&'d', &mut 40), + (&'e', &mut 50), + (&'f', &mut 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_values_mut_empty() { + let mut map1 = MAP_EMPTY.clone(); + let mut map2 = MAP_EMPTY.clone(); + + let vec_seq = map1.values_mut().collect::>(); + let vec_par = map2.par_values_mut().collect::>(); + + let expected: [&u32; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn map_seq_par_equivalence_values_mut() { + let mut map1 = MAP.clone(); + let mut map2 = MAP.clone(); + + let mut vec_seq = map1.values_mut().collect::>(); + let mut vec_par = map2.par_values_mut().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&mut 10, &mut 20, &mut 30, &mut 40, &mut 50, &mut 60]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn map_seq_par_equivalence_into_iter_empty() { + let vec_seq = MAP_EMPTY.clone().into_iter().collect::>(); + let vec_par = MAP_EMPTY.clone().into_par_iter().collect::>(); + + assert_eq3!(vec_seq, vec_par, []); +} + +#[test] +fn map_seq_par_equivalence_into_iter() { + let mut vec_seq = MAP.clone().into_iter().collect::>(); + let mut vec_par = MAP.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [ + ('a', 10), + ('b', 20), + ('c', 30), + ('d', 40), + ('e', 50), + ('f', 60), + ]; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +lazy_static! { + static ref MAP_VEC_EMPTY: Vec<(char, u32)> = vec![]; + static ref MAP_VEC: Vec<(char, u32)> = vec![ + ('b', 20), + ('a', 10), + ('c', 30), + ('e', 50), + ('f', 60), + ('d', 40), + ]; +} + +#[test] +fn map_seq_par_equivalence_collect_empty() { + let map_expected = MAP_EMPTY.clone(); + let map_seq = MAP_VEC_EMPTY.clone().into_iter().collect::>(); + let map_par = MAP_VEC_EMPTY + .clone() + .into_par_iter() + .collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +#[test] +fn map_seq_par_equivalence_collect() { + let map_expected = MAP.clone(); + let map_seq = MAP_VEC.clone().into_iter().collect::>(); + let map_par = MAP_VEC.clone().into_par_iter().collect::>(); + + assert_eq!(map_seq, map_par); + assert_eq!(map_seq, map_expected); + assert_eq!(map_par, map_expected); +} + +lazy_static! { + static ref MAP_EXISTING_EMPTY: HashMap = HashMap::new(); + static ref MAP_EXISTING: HashMap = { + let mut m = HashMap::new(); + m.insert('b', 20); + m.insert('a', 10); + m + }; + static ref MAP_EXTENSION_EMPTY: Vec<(char, u32)> = vec![]; + static ref MAP_EXTENSION: Vec<(char, u32)> = vec![('c', 30), ('e', 50), ('f', 60), ('d', 40),]; +} + +#[test] +fn map_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashMap::new(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_empty_extend() { + let expected = MAP_EXTENSION.iter().copied().collect::>(); + let mut map_seq = MAP_EXISTING_EMPTY.clone(); + let mut map_par = MAP_EXISTING_EMPTY.clone(); + + map_seq.extend(MAP_EXTENSION.iter().copied()); + map_par.par_extend(MAP_EXTENSION.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend_empty() { + let expected = MAP_EXISTING.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION_EMPTY.iter().copied()); + map_par.par_extend(MAP_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +#[test] +fn map_seq_par_equivalence_existing_extend() { + let expected = MAP.clone(); + let mut map_seq = MAP_EXISTING.clone(); + let mut map_par = MAP_EXISTING.clone(); + + map_seq.extend(MAP_EXTENSION.iter().copied()); + map_par.par_extend(MAP_EXTENSION.par_iter().copied()); + + assert_eq3!(map_seq, map_par, expected); +} + +lazy_static! { + static ref SET_EMPTY: HashSet = HashSet::new(); + static ref SET: HashSet = { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s.insert('c'); + s.insert('e'); + s.insert('f'); + s.insert('d'); + s + }; +} + +#[test] +fn set_seq_par_equivalence_iter_empty() { + let vec_seq = SET_EMPTY.iter().collect::>(); + let vec_par = SET_EMPTY.par_iter().collect::>(); + + let expected: [&char; 0] = []; + + assert_eq3!(vec_seq, vec_par, expected); +} + +#[test] +fn set_seq_par_equivalence_iter() { + let mut vec_seq = SET.iter().collect::>(); + let mut vec_par = SET.par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = [&'a', &'b', &'c', &'d', &'e', &'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +#[test] +fn set_seq_par_equivalence_into_iter_empty() { + let vec_seq = SET_EMPTY.clone().into_iter().collect::>(); + let vec_par = SET_EMPTY.clone().into_par_iter().collect::>(); + + // Work around type inference failure introduced by rend dev-dependency. + let empty: [char; 0] = []; + assert_eq3!(vec_seq, vec_par, empty); +} + +#[test] +fn set_seq_par_equivalence_into_iter() { + let mut vec_seq = SET.clone().into_iter().collect::>(); + let mut vec_par = SET.clone().into_par_iter().collect::>(); + + assert_eq!(vec_seq, vec_par); + + // Do not depend on the exact order of values + let expected_sorted = ['a', 'b', 'c', 'd', 'e', 'f']; + + vec_seq.sort_unstable(); + vec_par.sort_unstable(); + + assert_eq3!(vec_seq, vec_par, expected_sorted); +} + +lazy_static! { + static ref SET_VEC_EMPTY: Vec = vec![]; + static ref SET_VEC: Vec = vec!['b', 'a', 'c', 'e', 'f', 'd',]; +} + +#[test] +fn set_seq_par_equivalence_collect_empty() { + let set_expected = SET_EMPTY.clone(); + let set_seq = SET_VEC_EMPTY.clone().into_iter().collect::>(); + let set_par = SET_VEC_EMPTY + .clone() + .into_par_iter() + .collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +#[test] +fn set_seq_par_equivalence_collect() { + let set_expected = SET.clone(); + let set_seq = SET_VEC.clone().into_iter().collect::>(); + let set_par = SET_VEC.clone().into_par_iter().collect::>(); + + assert_eq!(set_seq, set_par); + assert_eq!(set_seq, set_expected); + assert_eq!(set_par, set_expected); +} + +lazy_static! { + static ref SET_EXISTING_EMPTY: HashSet = HashSet::new(); + static ref SET_EXISTING: HashSet = { + let mut s = HashSet::new(); + s.insert('b'); + s.insert('a'); + s + }; + static ref SET_EXTENSION_EMPTY: Vec = vec![]; + static ref SET_EXTENSION: Vec = vec!['c', 'e', 'f', 'd',]; +} + +#[test] +fn set_seq_par_equivalence_existing_empty_extend_empty() { + let expected = HashSet::new(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().copied()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_empty_extend() { + let expected = SET_EXTENSION.iter().copied().collect::>(); + let mut set_seq = SET_EXISTING_EMPTY.clone(); + let mut set_par = SET_EXISTING_EMPTY.clone(); + + set_seq.extend(SET_EXTENSION.iter().copied()); + set_par.par_extend(SET_EXTENSION.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend_empty() { + let expected = SET_EXISTING.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION_EMPTY.iter().copied()); + set_par.par_extend(SET_EXTENSION_EMPTY.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +#[test] +fn set_seq_par_equivalence_existing_extend() { + let expected = SET.clone(); + let mut set_seq = SET_EXISTING.clone(); + let mut set_par = SET_EXISTING.clone(); + + set_seq.extend(SET_EXTENSION.iter().copied()); + set_par.par_extend(SET_EXTENSION.par_iter().copied()); + + assert_eq3!(set_seq, set_par, expected); +} + +lazy_static! { + static ref SET_A: HashSet = ['a', 'b', 'c', 'd'].iter().copied().collect(); + static ref SET_B: HashSet = ['a', 'b', 'e', 'f'].iter().copied().collect(); + static ref SET_DIFF_AB: HashSet = ['c', 'd'].iter().copied().collect(); + static ref SET_DIFF_BA: HashSet = ['e', 'f'].iter().copied().collect(); + static ref SET_SYMM_DIFF_AB: HashSet = ['c', 'd', 'e', 'f'].iter().copied().collect(); + static ref SET_INTERSECTION_AB: HashSet = ['a', 'b'].iter().copied().collect(); + static ref SET_UNION_AB: HashSet = + ['a', 'b', 'c', 'd', 'e', 'f'].iter().copied().collect(); +} + +#[test] +fn set_seq_par_equivalence_difference() { + let diff_ab_seq = SET_A.difference(&*SET_B).copied().collect::>(); + let diff_ab_par = SET_A + .par_difference(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!(diff_ab_seq, diff_ab_par, *SET_DIFF_AB); + + let diff_ba_seq = SET_B.difference(&*SET_A).copied().collect::>(); + let diff_ba_par = SET_B + .par_difference(&*SET_A) + .copied() + .collect::>(); + + assert_eq3!(diff_ba_seq, diff_ba_par, *SET_DIFF_BA); +} + +#[test] +fn set_seq_par_equivalence_symmetric_difference() { + let symm_diff_ab_seq = SET_A + .symmetric_difference(&*SET_B) + .copied() + .collect::>(); + let symm_diff_ab_par = SET_A + .par_symmetric_difference(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!(symm_diff_ab_seq, symm_diff_ab_par, *SET_SYMM_DIFF_AB); +} + +#[test] +fn set_seq_par_equivalence_intersection() { + let intersection_ab_seq = SET_A.intersection(&*SET_B).copied().collect::>(); + let intersection_ab_par = SET_A + .par_intersection(&*SET_B) + .copied() + .collect::>(); + + assert_eq3!( + intersection_ab_seq, + intersection_ab_par, + *SET_INTERSECTION_AB + ); +} + +#[test] +fn set_seq_par_equivalence_union() { + let union_ab_seq = SET_A.union(&*SET_B).copied().collect::>(); + let union_ab_par = SET_A.par_union(&*SET_B).copied().collect::>(); + + assert_eq3!(union_ab_seq, union_ab_par, *SET_UNION_AB); +} diff --git a/third_party/crates/hashbrown-0.14.5/tests/serde.rs b/third_party/crates/hashbrown-0.14.5/tests/serde.rs new file mode 100644 index 0000000..a642348 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/tests/serde.rs @@ -0,0 +1,65 @@ +#![cfg(feature = "serde")] + +use core::hash::BuildHasherDefault; +use fnv::FnvHasher; +use hashbrown::{HashMap, HashSet}; +use serde_test::{assert_tokens, Token}; + +// We use FnvHash for this test because we rely on the ordering +type FnvHashMap = HashMap>; +type FnvHashSet = HashSet>; + +#[test] +fn map_serde_tokens_empty() { + let map = FnvHashMap::::default(); + + assert_tokens(&map, &[Token::Map { len: Some(0) }, Token::MapEnd]); +} + +#[test] +fn map_serde_tokens() { + let mut map = FnvHashMap::default(); + map.insert('b', 20); + map.insert('a', 10); + map.insert('c', 30); + + assert_tokens( + &map, + &[ + Token::Map { len: Some(3) }, + Token::Char('a'), + Token::I32(10), + Token::Char('c'), + Token::I32(30), + Token::Char('b'), + Token::I32(20), + Token::MapEnd, + ], + ); +} + +#[test] +fn set_serde_tokens_empty() { + let set = FnvHashSet::::default(); + + assert_tokens(&set, &[Token::Seq { len: Some(0) }, Token::SeqEnd]); +} + +#[test] +fn set_serde_tokens() { + let mut set = FnvHashSet::default(); + set.insert(20); + set.insert(10); + set.insert(30); + + assert_tokens( + &set, + &[ + Token::Seq { len: Some(3) }, + Token::I32(30), + Token::I32(20), + Token::I32(10), + Token::SeqEnd, + ], + ); +} diff --git a/third_party/crates/hashbrown-0.14.5/tests/set.rs b/third_party/crates/hashbrown-0.14.5/tests/set.rs new file mode 100644 index 0000000..86ec964 --- /dev/null +++ b/third_party/crates/hashbrown-0.14.5/tests/set.rs @@ -0,0 +1,34 @@ +#![cfg(not(miri))] // FIXME: takes too long + +use hashbrown::HashSet; +use rand::{distributions::Alphanumeric, rngs::SmallRng, Rng, SeedableRng}; +use std::iter; + +#[test] +fn test_hashset_insert_remove() { + let mut m: HashSet> = HashSet::new(); + let seed = u64::from_le_bytes(*b"testseed"); + + let rng = &mut SmallRng::seed_from_u64(seed); + let tx: Vec> = iter::repeat_with(|| { + rng.sample_iter(&Alphanumeric) + .take(32) + .map(char::from) + .collect() + }) + .take(4096) + .collect(); + + // more readable with explicit `true` / `false` + #[allow(clippy::bool_assert_comparison)] + for _ in 0..32 { + for x in &tx { + assert_eq!(m.contains(x), false); + assert_eq!(m.insert(x.clone()), true); + } + for (i, x) in tx.iter().enumerate() { + println!("removing {i} {x:?}"); + assert_eq!(m.remove(x), true); + } + } +} diff --git a/third_party/crates/rnix-0.14.0/.cargo-checksum.json b/third_party/crates/rnix-0.14.0/.cargo-checksum.json new file mode 100644 index 0000000..886d564 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"fcdcfcbe69ba219427d7e4f0435343775127b3dc292fac94a5729ec7d5e5e804",".envrc":"1d26c74fd25a4c3dbb09e029fc609588da499fd4af2a41c88f6316c7f8c54cf1",".github/ISSUE_TEMPLATE/bug_report.md":"e029cf740ebfff7edd8ac7a71914cdd06d0dbb5d2c6a82c739aaf0f3d9fe7e90",".github/ISSUE_TEMPLATE/feature_request.md":"4589c7cf6d0d04b692ea0a4d99187488d9631bf1c9d4712aa41478c0907dea3f",".github/ISSUE_TEMPLATE/question.md":"e555a3b9fe9e67aeca3245a5a0162a9fe08516603989a80112b001a1c91b7b67",".github/PULL_REQUEST_TEMPLATE.md":"2eb53504c7972ee90a450a53f651694b73a0c1c9d1f68d1e09b9650e682b96e2",".github/dependabot.yml":"883b95e3be554fbadd92b315e4a8c6ea6ca688b64924e22dd61222b07f683507",".github/workflows/ci.yml":"565bb7e946d21cb3d1141d87422df88536ca5c84de0f9bbc7c79c623583e99d9","CHANGELOG.md":"e98de826b40a296bd75050d744b71a1a4aa6944e29f36ef1c2d38c3788152dd0","Cargo.lock":"ab7e6cdb7273dffd1189bdccea6721dbbf0cf4e6f16ac9807c3bd299efab4492","Cargo.toml":"1710fd19c321d58563c6a375e6c4fc26c94511049bcfb3024e426d16eb4df83a","Cargo.toml.orig":"663ac3c05de129104746eeaeef3b6a6821eb6af5b5fff4834cb53eb317829ac5","LICENSE":"6c54a9750f1e6da4ad6618c569f2541b1df31921e2b30651886fc8893dfc3e76","MIGRATING.md":"baff376c0509c119628e318ffedeed21703f8ea32db8de743014643b7e2104c4","README.md":"4a09818de05e456506d5ee150a73b8ff92aaf6897ec8def03d3c9688c82a91a2","benches/all-packages.nix":"935f239a576caa554e546072772039f6efcbde2f2e6568733b8857fe476c5604","benches/all-packages.rs":"e64ed71c76a13eba2c2444062423122f5ad8ced00ab6de1951e19e1806313926","default.nix":"d84fab688ba7f236a7ad9db1eedfa8dd68bfec1271c5aea81cc0ecdc84d3ea84","examples/dump-ast.rs":"b3759df9673065fc661258f32a50aaae25b5573faef986dc47658ae3f6c94cc5","examples/error-report.rs":"ab3f5357d3ff3816b2355ad526fcfc9a33a8c5dc5dd434cfcd82a4b951643e52","examples/from-stdin.rs":"77726afba4b0c79b46e7efd2a2dc940bedb0bc9e30dca37d7443b33e306433d1","examples/list-fns.rs":"01d3f433cbeebfedc1c5d8106db0f1e9965b587c30244e66b504b98828e6d433","examples/preserve.rs":"971a77999a84bc11b9a3afe179bd8e51f4de475009e776c42890ac02c2eaf030","examples/test-nixpkgs.rs":"0924d62302f5486a87d26597af6f78497a6ed2439452efe14b5262d3644a21be","flake.lock":"a71d5cc0ebeed8335099205ad2e6eece037f39faf609de2b2afd83c1d0b1c0fc","flake.nix":"bc94dbe872df56b1b16289dcfdd5db0a627fd6165331c2d11b5bae8b2481da57","rustfmt.toml":"f74204a6f92aa7422a16ecb2ffe2d5bae0f123b778d08b5db1a398a3c9ca4306","shell.nix":"6fd207b4354fc12c29f603ba106d4bc5a6becbc0f13de4f90846ee10b2054bb1","src/ast.rs":"0307dd2b362ce111a4b730318c7df75f1d62534acf7a4a295972ae5369e02141","src/ast/expr_ext.rs":"53afc86db8b404aa7fb1f2a7c47a925cb83bea95cd3b5e52b44963439892be3d","src/ast/interpol.rs":"7d9c8baa98fb47d691e55a1106f5e457c6c786dbc00d27e015acf6f67c3248e1","src/ast/nodes.rs":"950d9e7c0fe9320e4e5ce19aaa1c06aeab6fc3236199a7ef9f395180ae3eb423","src/ast/operators.rs":"51ae735d38623d0490efd21d7060806aadbe1f91589f5cde922c1b50a0941a98","src/ast/path_util.rs":"8dfe591cb762e630bc0271c2a1875be0b6c3b35876af118cfd4edc055e1cf34c","src/ast/str_util.rs":"448e5e2805552e0a386569e8f497ef10802c5b7d45360fa345b0dd1b36b82d3f","src/ast/tokens.rs":"7d6aec7ed91930cae7d472df800e6eccff4afe855084928e22f0460d1a0017a3","src/kinds.rs":"3a06fd766de635066eccabcca90f5698458d7bf868a9fb12410f90a8766a6d0e","src/lib.rs":"dd33d6ab292d2c1c2f303392fc5a34ebb96106b61b6a3ea32b97fcc4e6f007ca","src/macros.rs":"6f222ffebe7d2b7ba9d653e050ce680cb34f5ccad5046b1a74ca000e27cf10ed","src/parser.rs":"facbcf26a37d0702da21aab5ec65bb5e69e8b4fd70fd8b1fd33ad54610c5b56e","src/tests.rs":"4bbdf0c133806aab2404e6449af3c4669b4c9632206b10b60db2e2f4a2c05f96","src/token_set.rs":"5b2b9f7a8dc04a0b9334bf19b38bf51dc7237eea3c1d6d07df06f3e94b948079","src/tokenizer.rs":"90e0db5df66f75a6098277f695f79f98098b099534d23d9e8ef8547d5d690712","test_data/parser/error/dollar_ident_attrpath_issue174.expect":"01262a025ed92dadfbcc3ec6e4fa70020a2d79d42e85c330cff76b0e35eee4a9","test_data/parser/error/dollar_ident_attrpath_issue174.nix":"213745923795602e58733d53a142ccbf7a46f15820a3e8dd351fe03c387792dd","test_data/parser/error/error.expect":"22f46b02e4c35c07a42f68c9096d2c97e520e4411da6beaf5146f128210dde87","test_data/parser/error/error.nix":"ab96e082ceb9a8fd295b1b9770d1a092fecc957f9dfa9393a51572db005f6510","test_data/parser/error/extra_comma.expect":"83cea8dfcdccb17eebda361f9d858082012b2090f6ab50a9f8b7ec05a65e6140","test_data/parser/error/extra_comma.nix":"a67d8cf479d324f353bdbaff9e94772d6acc74807c07959fa0b51e83f431b258","test_data/parser/error/formals_double_bind.expect":"8659ab05254da887bebff84e60c9ddf9aead1fc10d12594455e83826de39db1b","test_data/parser/error/formals_double_bind.nix":"ad473bbab713d5fe1c2cbddebe176962d1fab8a03e76a348347f7587c7ab27d5","test_data/parser/error/inherit_from_late.expect":"fbda47c9f72a1b48f9d312c33f65dc6b054258a717d9c5fa4bac5cb158ef35d7","test_data/parser/error/inherit_from_late.nix":"51d769bd192f1c504a3de48f5d2bafd60cde2e11dba9f24cf4277c3da7e6f534","test_data/parser/error/inherit_incomplete.expect":"21d5815a1ee6c501de0d893397f705839c5c49bc9d1cca4a8402245edb7a2c79","test_data/parser/error/inherit_incomplete.nix":"ac02c3c2fb22d5b5328848b6b655746f5b1658dab3e24613691e58a05dc265d4","test_data/parser/error/path_bare_tilde.expect":"b8898ae0983ce6ec094e0a16d9e82d3df27c30e796c2f5e57b50f8a4abe2288b","test_data/parser/error/path_bare_tilde.nix":"7ace431cb61584cb9b8dc7ec08cf38ac0a2d649660be86d349fb43108b542fa4","test_data/parser/error/path_double_slash.expect":"9cb14b765fed1dc836722a50bcf08ea72b00d5e37d33f3944bee825b0719a1d8","test_data/parser/error/path_double_slash.nix":"aacd33f3306b6050e1ba12998f9e85c2c99dfeb43f0c50a490bc0a3030dd2f5a","test_data/parser/error/path_interp_no_separator.expect":"4a0447d0ff5e884aa349333f89f422bf79a6fc7a75b266f36fdb28895979fa21","test_data/parser/error/path_interp_no_separator.nix":"fd76e7497b77695c8a771c9cd6f0e80ca78d0e1f52be72318f31d6132231483d","test_data/parser/error/path_interp_trailing_slash.expect":"5e5536a274672274859a39ac13d6586ed0daf8c4859481d389a775d21d72d672","test_data/parser/error/path_interp_trailing_slash.nix":"4033fac7b9dfbcf5c9642649bd453760de95cedab9397737a56e43619d14a4f5","test_data/parser/error/path_multiple_errors.expect":"558b9644e96797fa2c75bd5c54dc99175baf8c14b7cd707ee95c64c5509d57a5","test_data/parser/error/path_multiple_errors.nix":"dc2b49f1c4e19afd20aeeaf396846b118e27ecb28da6429c8bf05e2966f5a357","test_data/parser/error/path_store_interp.expect":"9e016b5379a2493158ef3ff352b67f24f729be0ce51660f65105f8dbb4afd87f","test_data/parser/error/path_store_interp.nix":"0f7744723ef206810a7e64162b3716c94c46e3e4b0eb624fda9fbbf3672f7f3d","test_data/parser/error/path_tilde.expect":"bd79f89d951c6fcf94dc43077994895d4270720fc4b003d8c763d7ddef01943f","test_data/parser/error/path_tilde.nix":"7f41fe720e761f25d93654687506af637ba8c61fb28561e5398dbf538a4b6044","test_data/parser/error/path_tilde_slash.expect":"9bfd9d681402e1e7d8fd083ccc590461ce31d42a28b2e794621586daaaf146df","test_data/parser/error/path_tilde_slash.nix":"3a329a2e7654f11120e6fa6685d7bef9f8908c38fdfab910ccdf9e86ae73f6f5","test_data/parser/error/path_trailing_slash.expect":"f7de09d6bfc13bbd76d0a0a130380007c9f2fefe275cfc05d00c169486d196b3","test_data/parser/error/path_trailing_slash.nix":"5b4b5a8f73cf98cc065cf8c88d70cc1117bff195957784d92c3fe4dbab12087a","test_data/parser/error/select_both_errors.expect":"d26e2c8cf525eaa99e5eeb4cb464672e719bc63b2f0ff1275ca9215360d10dea","test_data/parser/error/select_both_errors.nix":"8cba67b02220d9cc4f1f6909f1c3453230c24f5512d165843782e868a8066f27","test_data/parser/error/ws_belongs_to_root.expect":"6377c97f36c777529ee4ab7563105fac86ece460f5f2d4c5f14d39723863f509","test_data/parser/error/ws_belongs_to_root.nix":"b95f794a00af86ac86ef6ec3985f844fc72e11f067d1018fe71a245cd83f3b0b","test_data/parser/error/ws_belongs_to_root2.expect":"eb72203f16e6bc496123ca08a158873419436473c86e27fc824af4a280b41857","test_data/parser/error/ws_belongs_to_root2.nix":"a784b477493644e929892b35b42d4ab52d7159b13a2b69bd6ed552f6cbfa7a3b","test_data/parser/success/apply.expect":"5dc4e0e1672341050ce1d3465a2b7fa1cf4144b289df00c86206f0706969123a","test_data/parser/success/apply.nix":"8826af7c8fbf81ef13122ec332a5ce06e0067b900390e175fd1fef69a5239577","test_data/parser/success/assert.expect":"f1bfa54f4b0072b6aa21a4a0a934f2697a90f9f6aa30ffdfd456a14bdcb3045f","test_data/parser/success/assert.nix":"6bf37c816a05512fc7269c316630dccc7920d22efd79d762d556d6d44c3a3f67","test_data/parser/success/attrpath_ident.expect":"15c3d8242db96ba48ae8e67f151c429b35cd16053b4cfd93ce2d723836cc005f","test_data/parser/success/attrpath_ident.nix":"dfbb4116f96d5fd359553ea0c22f0bb193c30f8f511c435781539ba48f85d121","test_data/parser/success/attrset.expect":"3ad0be5f86a4be2a4f43faf18a5729c304f6500a959cb6726b2198fb25a22f3a","test_data/parser/success/attrset.nix":"70191aff6e8e8f5ed4eb5ea2a797c4fc2b61b6ebe7c379fbb2fded21e2dfac69","test_data/parser/success/attrset_dynamic.expect":"46356c1cd17834c321c458b4410c53d90e3b7fc07a0aaca935977890f3c626bc","test_data/parser/success/attrset_dynamic.nix":"1eed00b970fa930bd260e3b3d425146dd284c0a72c562cb8153bf06a3aa97ea4","test_data/parser/success/attrset_empty.expect":"9ac4e092c064a6bf01ab3b7374e8bb1110f64c6330a4b645e593fb0ee3713441","test_data/parser/success/attrset_empty.nix":"ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356","test_data/parser/success/attrset_rec.expect":"b596c65fb37fddafdbba87508f4ed4c114f8f696d275833b1bd7b1609b7727be","test_data/parser/success/attrset_rec.nix":"480107e889b5500bc9a1909b2a8e8dfb3ae0f3359a40b4a891857348546e2228","test_data/parser/success/bool_arith_ops.expect":"31f5526a8b51d8fa0051adb0956827d0fb2456259633a56709baa1c0ca7b14d4","test_data/parser/success/bool_arith_ops.nix":"3e75f0376b74fd21694043f7d1bcf2913274d60a4b7489d2f5bcb2c6356084f3","test_data/parser/success/bool_ops.expect":"6c1c5f29dc44fc726659813689954266482e20c6dcd43e1f7522976190c96c12","test_data/parser/success/bool_ops.nix":"3916b3d423564a64452233dc0057645c359c059087bcce282c77d29db73df999","test_data/parser/success/bool_ops_eq.expect":"5493a9311d759738c8c77e1f665b226713a95c89dce5b4f2cbbadd6d02180a7d","test_data/parser/success/bool_ops_eq.nix":"1090c7124d6ba4fe92f13952812695459a819b9da1028ae9551ca92fca384b02","test_data/parser/success/cur_pos-as-arg.expect":"78c7226c5bce7269168b5a97c9a9029a1532762c33b064b532a011b69ac49c16","test_data/parser/success/cur_pos-as-arg.nix":"e952d92994cacca4538ac4453caba8534a201c45b4bc405e32c6cb87d31da045","test_data/parser/success/cur_pos-as-ident.expect":"f1969ed241a1946f5a5c716279b79f39a10699a34c6df647c9d45eb84af73344","test_data/parser/success/cur_pos-as-ident.nix":"176c80ce6bae6c1b9bf52096e40dd40c70c1af1ef60387276b7c7ec2c59bc7c3","test_data/parser/success/cur_pos-lambda.expect":"388e6a05f568b997a93cec12c47d8780a97fa2621269f2a01c1ce30b77f037e3","test_data/parser/success/cur_pos-lambda.nix":"db46269968d09dd6052d042908592fd61dad0cd86cf3829fc1e8bd4b6b58fb16","test_data/parser/success/cur_pos-no-shadow.expect":"ed7a3e54ffd78bcc98d7b4e00ecdbf400aaa185f6644a4d7a8ba27a24772266a","test_data/parser/success/cur_pos-no-shadow.nix":"8c62c3cd453aaecdebad2c31e9f3b1eea42ae6744264085f4ac9ed557ce19f77","test_data/parser/success/cur_pos-pattern-bind.expect":"1dcbe6233261546c84c3be9014ef25f53531de41161ad6d3288c4a49d1772f11","test_data/parser/success/cur_pos-pattern-bind.nix":"9bec524649f1caf8a08d5486c3b3eceebcc3c62d112d621718458d7ab938d34d","test_data/parser/success/cur_pos-pattern-field-default.expect":"abf746354db0b54ece060cf994cb71d4c08868c1dec081d43e7bf0d20ba58ec7","test_data/parser/success/cur_pos-pattern-field-default.nix":"60fc3f7a4581176cca6e938f1f7a9aee739d0d5d988983dac55f174b30fa541d","test_data/parser/success/cur_pos-pattern-field.expect":"3565d9ed2eba05da8321f7568a9a2891da39324b734ebf95458f6dd21fa0bf96","test_data/parser/success/cur_pos-pattern-field.nix":"f5813cecdfa5f539c6a54c4cb75d378066defc3c26a42bfb392c58a2595572da","test_data/parser/success/cur_pos.expect":"9b33ef41f07a33ea97c8d510791cc00d05ff1d485b6e3f9a92217957c15caa07","test_data/parser/success/cur_pos.nix":"681d944c0e6f16f702ea0ebbdd04c4e8d7bb0f44299f7ff45d6a7118ca414ee9","test_data/parser/success/docs.expect":"7fb56fe73afa02cdb09441f8c65ac505ea2cfa941928823eb3bba672cad936f0","test_data/parser/success/docs.nix":"14aa3603895dec714eaa50f91e408aa10fc533e8c860d943529e4e147538645a","test_data/parser/success/has_attr_prec.expect":"895747be329dfc5c27d01e757d48078884430d190d3be500618fe926077e617a","test_data/parser/success/has_attr_prec.nix":"92f076f3111c480de68876b9ac082af8a420c575aace766344c0f8f2d7307482","test_data/parser/success/if_elseif_else.expect":"40c85a70409ef1a97b970a27fc652bcba10a03ad257bd05f1d39a6200dd7f0cc","test_data/parser/success/if_elseif_else.nix":"01b537826ed2c1acd019f897f5adf8c43bb8c729a63ad068b7de71143f09ebba","test_data/parser/success/import_nixpkgs.expect":"c1b8f1e7e567a85da7678edcc974683505a1f2e5431cb005fe82440dcc661914","test_data/parser/success/import_nixpkgs.nix":"31844e4c58792fdcd0a13b32c362e473a07b1d066fcbd46038e621eaedc894b9","test_data/parser/success/inherit.expect":"323ba1fc8250dccf1db649a5ea0a8307dd70f2e08c45a582073fd5187bc335b5","test_data/parser/success/inherit.nix":"a48e8ed8d49ef8686191e3991408d9bdfe73e7b9dd6a35557a7f1c11d8eaa598","test_data/parser/success/inherit_dynamic.expect":"a11417b52af956ae194ee3e6bbe7262ba1f3084b53a6a635dc76037e0a3e1047","test_data/parser/success/inherit_dynamic.nix":"43ef55ccde3dc27752cb58210754739829fe39f2b34d488284a91f68cef3ac8a","test_data/parser/success/interpolation.expect":"0adf3fc11094e94099afbca366605e1610f767e6cff2ec9b7b9a100e23b66f67","test_data/parser/success/interpolation.nix":"4ca4df8d7abf1b4c74087cb19e0ba4c56eac56e8c66f34f1b5acfaf2a7032c5c","test_data/parser/success/lambda_is_not_uri.expect":"ea1de79fe0953193bcde70c117a16cc642bd7851225cf0aede52674202be1648","test_data/parser/success/lambda_is_not_uri.nix":"2679ace7f9e749b076bb709efe98204bc1a5031770ee2e099349462382cd0579","test_data/parser/success/lambda_list.expect":"2ca1457c72f940a2523299114ec0d663e5c54179a1766c6c19bec995769f9483","test_data/parser/success/lambda_list.nix":"47ea4655d01c453402993e03887836ac3bb07adaf6054a6dd487fa2424b73786","test_data/parser/success/lambda_nested.expect":"1e2d16ee2167a7abd8f669f4e1fcf3db09eeb022171dc71f3a5acc148082e7a9","test_data/parser/success/lambda_nested.nix":"edc937e71d82484ce34a187600422dce3cdbbad0c353da35147f8d6f2994f0e2","test_data/parser/success/let.expect":"19f8c24de47f02394b5b1bc3dd1ac051316cf64e6b278f6e988986fa58142b59","test_data/parser/success/let.nix":"8468f72abdf2d416f034a32c95696e062458e7fb9e12b171703a4a2e4720e0db","test_data/parser/success/let_legacy.expect":"34593dd19849d59a19ff1d39f0da925908585b9490e9cfdc004a3b566e7a17ee","test_data/parser/success/let_legacy.nix":"b7a83de72713b0097ef341b02bae665c4deb61d3085cdd89572765f67cb14866","test_data/parser/success/list.expect":"adae23eec4c3e2ab3ec45c4ea04d0930179b269eead1c53d736b77ea713a6b2c","test_data/parser/success/list.nix":"a1314bae234981d632535abc8f7bf00210aac67ea5e49b5c6252ecd963c75d19","test_data/parser/success/list_concat.expect":"6b585328572e373d8c5fa28c093e641c276339376d67dc47501b88a9955db669","test_data/parser/success/list_concat.nix":"05291dba1c1853cd1e509d68630b81e391d7abcf36ab80d3f9a79aa891de50fb","test_data/parser/success/math.expect":"213e348096cfc10e6bc3f57d1de4175c498f18f7894c3ed3600a19abded5be1c","test_data/parser/success/math.nix":"143a57d9bf045dfc658a42d9d14e9acbc70d39f20b6f9e30a25258066dfea1f3","test_data/parser/success/math2.expect":"ea71d26cd0e6e3bff87adaea5e27a650a70716d622c2497d5460637236819f41","test_data/parser/success/math2.nix":"2cc13451aeebdec2dcfd6712c71804e4416e12cb0bb48468b59b5ed953e0e829","test_data/parser/success/math_no_ws.expect":"24d346c0f632416572841e38f0dd07fd97dbad3771d9ce2da81e694fc09a9bf4","test_data/parser/success/math_no_ws.nix":"bbf1bee1b75930cd72023c8f1ec6080cb9aacd408a0a309ceb0df6f6a837d6f6","test_data/parser/success/merge.expect":"6a4c1760e456cd42fdd190222346f7d20a29e206ee1a1c2b5f333dbf8518c41b","test_data/parser/success/merge.nix":"e2175ee885b2c821f8e9eef1b4e08d9012a5bcd5177cf988e9b0b35a5ce4373a","test_data/parser/success/multiple.expect":"1155e066ead409410d190a469ed7b3e0651fbc02d94100b3f217af38cae8dfe5","test_data/parser/success/multiple.nix":"f1e10dcf42c54160c9fed5006e3b2cccb8252f45e29bc0ddf717d1ae0adf59e5","test_data/parser/success/number_list.expect":"abdf4d81c7a7e0601ea39a79765a4091918e8037e2d91609ac335752027fee8d","test_data/parser/success/number_list.nix":"45bfb90b34849c8f829290e0364c2e2c4a8632a6500cf2f87ca279452d5f5b51","test_data/parser/success/operators_right_assoc.expect":"a09a763c00128e3abc7acf514f3c23222f2e5a952defe0ae8fb2c72dd66bfe01","test_data/parser/success/operators_right_assoc.nix":"7ffb0494203cd08eff15a208aed06d2b6d13a48d11c846fda050d7edf0e74283","test_data/parser/success/or-as-ident.expect":"21c3b9ed958c77353b8ccad7b5a727f0a33a41c32ff1a27b127950a357292742","test_data/parser/success/or-as-ident.nix":"b0d9813f1404c3e40045a559ccbd28cdd35e12457b99234bff9ce000784fc081","test_data/parser/success/or_in_attr.expect":"eb7c713859fee41975dad4a354b5e6785132a9a0861a7bb6536294400828b4f6","test_data/parser/success/or_in_attr.nix":"7fbca3be8d741bd3d91e9a9c34c212b54017e58e20c2fc0f61465d0a1fc3a67b","test_data/parser/success/path.expect":"d0d1b3c146f480a0efb98631db61fdc8b747bac15f1187053eb0663096e1a0af","test_data/parser/success/path.nix":"afd72fa405fcc6d24263495e5511d91a96d16d4250dec76ae3bf4174e5c27028","test_data/parser/success/path_abs_interp_start.expect":"ee751bcefea4e139eb87dd252c94665b9b81a63ea807e8bfefdd06e7febc1889","test_data/parser/success/path_abs_interp_start.nix":"ece1c4989571cc0ce1aec1ff66843082bc8135435a5e60d4cc27cb2423019e75","test_data/parser/success/path_complex_mix.expect":"5dd4b04d532f5f8c17b7fbc263783e07d1f7a60850057808f7c99af30a6daa2c","test_data/parser/success/path_complex_mix.nix":"efe72ab51cc3de4ad627be8559530bfcc9d93b45a14bb4696abc3bccd9850409","test_data/parser/success/path_interp.expect":"21789a751afa245eb375af95294079bd1ebd16ecb5226cad44f6b908b438e546","test_data/parser/success/path_interp.nix":"cd98461695f717809f9d163af99fc3dcfb1a315e672c67c40aef52c84827429c","test_data/parser/success/path_interp_no_prefix.expect":"37b957a26669991588b05416b6a195d828c199e1772bfce7abd88302b93e8983","test_data/parser/success/path_interp_no_prefix.nix":"0acf6fcedbc272d14bb3e45a1cce99db94974152a19e445a020b25f1a99f6a42","test_data/parser/success/path_no_newline.expect":"96ed256ee676f20062944a7d592f56fb8ff4a591585f2092e277e893f73e4f68","test_data/parser/success/path_no_newline.nix":"fbd3deff9ff62107cc0c5a05abed01ef17b7e03ccbc2aaed70c80d46370ada7b","test_data/parser/success/pattern_bind_left.expect":"6693668a70a6bf7430e82db3a62c09000a8ce24dd8a8efcac616cebcbe81e102","test_data/parser/success/pattern_bind_left.nix":"594b6ccf3c3103ac217c4de7abcb43df79266949ff2f7007e56613d37810b4e1","test_data/parser/success/pattern_bind_right.expect":"13960afc2cba850d37894b60f7458ff8498e3ab266422327ae2426604e91fb3f","test_data/parser/success/pattern_bind_right.nix":"38727bc5177f804bc86a80ea4e398ef1c6ed6807326d51f89dc93e1d17100321","test_data/parser/success/pattern_default.expect":"37588be2e15ca66047d73fcce8b85431874150803a9351ad6d90e864a70a3bf1","test_data/parser/success/pattern_default.nix":"4061cbd9f03d1f74cb6d45e6527fe5cfb65dda476fb7217bed0487d621b74ce3","test_data/parser/success/pattern_default_attrset.expect":"e512ca4bbb76fdea2fa89191c5ba79c631247d14d85be558653a7c08603448d7","test_data/parser/success/pattern_default_attrset.nix":"7f5a7fe0db55cd9c2310589cb54064204f3dae34d3a1c9059075b71f7a42b124","test_data/parser/success/pattern_default_ellipsis.expect":"64f28c64900813f594766a58f896fb2036349892a98680c5d90dac568a67e78f","test_data/parser/success/pattern_default_ellipsis.nix":"72d36593a7d026a444e578118bb526207ae1e034f1de7374172a5ef020fa412a","test_data/parser/success/pattern_ellipsis.expect":"e81e9063a6b32729dd83f98ecbea52de4df29923a9c5fd164816896d9fadec2d","test_data/parser/success/pattern_ellipsis.nix":"da03f3437de0a5024d36a0499241bd26f541e5fce170e30b470b03f687451a84","test_data/parser/success/pattern_trailing_comma.expect":"4e8656b30a3d7b7cbe5c17471e757ab248e20e4fa42d8681f8a9a7bbbaa06a02","test_data/parser/success/pattern_trailing_comma.nix":"f921536d794b09862c2b430fa94a0c6da9bb82794625dcd12761ce2bd200b3c0","test_data/parser/success/pipe_left.expect":"6bf0899fc50bdb2ea569ba2885d416657a049aeeaaa97f1134ccd79374f83b9b","test_data/parser/success/pipe_left.nix":"3fc61c1f978c7dee1af7eb55b59c53075b971478d9ef4403c167b728db38d00e","test_data/parser/success/pipe_left_assoc.expect":"f5dfd0054e9146d3168e2d03b3d41cea7664147b7df2563eb132373e6808234a","test_data/parser/success/pipe_left_assoc.nix":"a612447be59b2159b7b9281040c1a83a82f4d80f97d5060eaffde825b00cb074","test_data/parser/success/pipe_left_math.expect":"667f840f1296d39b507f842926ab75a3bdd16793547754c2b01be912f9f0d624","test_data/parser/success/pipe_left_math.nix":"cf89fb156438883b4e03369020ec0537bd5577a87a2cff0f4aa477193a90e721","test_data/parser/success/pipe_mixed.expect":"fc67924d665b32d6b8e332778519d7bbb0300f9595f99fe92237bea8d2b09c09","test_data/parser/success/pipe_mixed.nix":"a2a25b14e01de1fa5ffbe0fef089eb098168995acd65ceb000f2bc768a773fcd","test_data/parser/success/pipe_mixed_math.expect":"5977ce987191e5190436625446b1aba303b0e6379e2e37877d4939c044049323","test_data/parser/success/pipe_mixed_math.nix":"64f300d81f66c64809b3c1260558d1c1ecfb52770475baddfd1aaee4e822acbb","test_data/parser/success/pipe_right.expect":"ad0c46c239e60728452e703fb48b04d8057e14214277dba8e76a2c01d63a9c99","test_data/parser/success/pipe_right.nix":"83b0da20c798d42764b7d0a1f2c5f746514417016b5489f6b1919be27ea03f63","test_data/parser/success/pipe_right_assoc.expect":"dea1ef5a62e889ebcb3b11088c44ea6430c6dfbf132be341f97327de54c19be3","test_data/parser/success/pipe_right_assoc.nix":"0fc7be794cff04edb76cbd8a755e0f00770321cfae8577289a759cc0e886fcaf","test_data/parser/success/pipe_right_math.expect":"214e584b834aa6042cc2eb0d0c943a8f8c3bb72e5bb3910a2e29ebb94150a944","test_data/parser/success/pipe_right_math.nix":"4259e015b26fc4801fedea1373c588944b1d1535a44341a19e436da2673910e3","test_data/parser/success/select_default.expect":"2e1a96af0c6844b5f7f742429f98535bef77fdcfe5d232c0d7e453ec43ee1c39","test_data/parser/success/select_default.nix":"86b4ebbe2090b9adef68562591da961cad5b4c46018e2850ca819eb9b3ece85e","test_data/parser/success/select_ident.expect":"e6240ba8ab4fc1cb1e3b0bc596a6c6974a15e3f01aafdb51da3036c7b8f5960a","test_data/parser/success/select_ident.nix":"5509d18a8093bf49f4814cb919b67420450a64de047d36299f597fc6055ff462","test_data/parser/success/select_string_dynamic.expect":"bafcdfc4d878de52ca6cff14e82972584913990bb32793387295583e5c50b5b2","test_data/parser/success/select_string_dynamic.nix":"7cd1a148faa443b3907d08375204e2aa075f15f3ef53b464a933c189172a4b23","test_data/parser/success/string.expect":"57e6af09831d9a287324117a658e7221ed3c3d2c034123a76728d36c88fd87eb","test_data/parser/success/string.nix":"0dc9cc2bd9c090187914c398943f3bde6afaff7efa81598c8f90ed058ede05ba","test_data/parser/success/string_complex_url.expect":"e070a72c2f21b1dfb1ea00575f2336af4adf4874265fd7eb4881c6cef9e0910a","test_data/parser/success/string_complex_url.nix":"f572e941948b34f5bbd12d6c6715e81a2bcf9a13a51ca09253efc521cc35b795","test_data/parser/success/string_escape_issue175.expect":"7c9bc85e307a5a3d4043f206e12b65a10a2261f9b889dbe23c353ffd2263ad91","test_data/parser/success/string_escape_issue175.nix":"7a0bace2b779cb981b5d0698bf202928c36884d73e54e0bc63e258f7ffa9832e","test_data/parser/success/string_interp_ident.expect":"2561944ebcf3b1552dcdc9dee8ea4de71c8dc377711477dbff64654fc309a11e","test_data/parser/success/string_interp_ident.nix":"a01560c95c980e1bb4597119c16b1027e40dbcfa267f07a963b7c030f1e9ee92","test_data/parser/success/string_interp_nested.expect":"fdae689d788158b6b21e2f0cc2936f5265a731ce3e051ba9c625948de24f90a6","test_data/parser/success/string_interp_nested.nix":"33ca7ed5b5cbf4088522adf1112a052f6ce7b5434c0feec9b3ff003735f8d140","test_data/parser/success/string_interp_select.expect":"3f5fe7cbf17d35c447cd076dba7f08465802d6d987cdf15c93ea8552db825da6","test_data/parser/success/string_interp_select.nix":"3a18b235e24ac7b58b54787769815ab6354e380ff589cd94f97ae10b0745409e","test_data/parser/success/trivia.expect":"d909a901eecdce347fd51a6c2d5b853b43f4368a8049ed7138e759e8cec58027","test_data/parser/success/trivia.nix":"8fd255498ca9656a75fe94230bca84a9cbb936753c0a088429bd45731cb04ece","test_data/parser/success/uri_various.expect":"1257e97b0c00f1c2a1b1440651daac0570768dac0ce9a20dff9ff5b4451bab05","test_data/parser/success/uri_various.nix":"44854a1bcd82c86930837087ae801213f65b9893cd02d1daf199cbc677cd1506","test_data/parser/success/with-import-let-in.expect":"f1d90ee7c2b8e5e76c4e43bb584765fce64524f9da72ae194309dc40de5a82f0","test_data/parser/success/with-import-let-in.nix":"098b11b2b245e7323df076282d076206d99d337f1e3d8fe718be5e54c59ac9cb","test_data/parser/success/with.expect":"d08a252144a1fc12b5c443d29f88c280429c1dd4bb122e16104fd362d80d5944","test_data/parser/success/with.nix":"751963ece23baa99102bbbf61126f5228b525bcbdc7c8b0719efc6e4d0cf15c0","test_data/tokenizer/error/path_double_slash_middle.expect":"6495415f85b8c159a23318f9c44616de7751973b1ee719c683c975d38f782b61","test_data/tokenizer/error/path_double_slash_middle.nix":"659bbb51f3a9115f6a9ca8938b9b67eb8c327cfbaff81674fd5fa439109abcf7","test_data/tokenizer/error/path_home_double_slash.expect":"758f5c59f3dcf2d0b7e0f944c5530ee82af1b0aefd0ca214b0c15f677020d2c2","test_data/tokenizer/error/path_home_double_slash.nix":"7a682ab3ef0fd577b347cbc851e8f52f8ec79cde969be5d783ea88171f41b4ea","test_data/tokenizer/error/path_interp_trailing_slash.expect":"e9eb90d7262979a95d0958e8721841f21317f7c87ac1ee50253d14440ba1b2f0","test_data/tokenizer/error/path_interp_trailing_slash.nix":"4033fac7b9dfbcf5c9642649bd453760de95cedab9397737a56e43619d14a4f5","test_data/tokenizer/error/path_tilde.expect":"1f9078213e4ab2e38d6b00d1ea266897bd38d1cfeb6f3bfc3d6639a776c272a1","test_data/tokenizer/error/path_tilde.nix":"73cafed4c2cba0743097670a0615e4958fd6ddae0ea12b077bffcc3581e9afd2","test_data/tokenizer/error/path_tilde_slash.expect":"1cbdb62a7ae081127a755811cdfc403864f0984922a55fece85ba298cbd043d9","test_data/tokenizer/error/path_tilde_slash.nix":"3a329a2e7654f11120e6fa6685d7bef9f8908c38fdfab910ccdf9e86ae73f6f5","test_data/tokenizer/error/path_trailing_slash.expect":"310d877af6e1481d3d6ae51ebba64bab2af1a663571defeceeca7f8d2aa9ed90","test_data/tokenizer/error/path_trailing_slash.nix":"5b4b5a8f73cf98cc065cf8c88d70cc1117bff195957784d92c3fe4dbab12087a","test_data/tokenizer/success/comment_interspersed.expect":"97121c8b678f1501d5f859f1901a6b839ce68ebf65e90b9fd700b7806e197863","test_data/tokenizer/success/comment_interspersed.nix":"175fb6f86abb6ca87925be4f3a760ecbaad7eb5202d17d52f39ee84116e9f6be","test_data/tokenizer/success/comment_multiline.expect":"f0945b616a2c3c0b630873901d5ae9cf5f4785547d271c72c7d880ce72ca2f96","test_data/tokenizer/success/comment_multiline.nix":"1c0ff118a4290c99f39c90abb38703a866e47251b23cca20266c69c812ccafeb","test_data/tokenizer/success/comment_multiline2.expect":"48fb74170acc75318dc6617ecfcd2a0970b81f8a73bdce0c8f8ab29f0cd9a6c4","test_data/tokenizer/success/comment_multiline2.nix":"4c2fb6a85c51bbb1651b6ba48caf673a342a0be55d73e31a872909eaf1863b22","test_data/tokenizer/success/float.expect":"196c328b439d0e13389bb5ee1acbb9b70b9bf06fef528fe00859aebd66b38f77","test_data/tokenizer/success/float.nix":"15eb66fe9ea54798236558c5d86fd9175e111e3c77a2abe45c041da1d5a751f2","test_data/tokenizer/success/float_no_leading_part.expect":"66882866f9b05c848583c9f0087c47a334c005870f1a302ef113d8d584a04937","test_data/tokenizer/success/float_no_leading_part.nix":"eb5bde5c0af226f06479c3608311e454b35d498b43a4010feff3f89fc67553e5","test_data/tokenizer/success/float_no_trailing_part.expect":"6ca45999ba68b87d1ad21ec8900dd1efde6474b6021ba614b8c24777cb22e906","test_data/tokenizer/success/float_no_trailing_part.nix":"b5f6d6610817503fe184b6c04afac552914961116ea70d1636a60218165fd220","test_data/tokenizer/success/float_scientific_lower.expect":"52b8e2ffb8d6828875dc8b68a5914ed5974954439426db6a8b7877aa5812678e","test_data/tokenizer/success/float_scientific_lower.nix":"6e8c3ab788def1637e2ebdb000c25574ef01b74d82770c007e376e5dd8486b44","test_data/tokenizer/success/float_scientific_neg.expect":"c30cfa2c3f3b72297879196c565f7395107e3c068faef2a44d5d3511d1d03e3c","test_data/tokenizer/success/float_scientific_neg.nix":"30f783b0e08a1ce0c6591e692cd37f0efe7dd375852840af55b8f86f309f0f60","test_data/tokenizer/success/float_scientific_pos.expect":"aa2efa95fc52e5e86ac7e2dd501dc5755a49ac5e2939e9dcc0e41680c4a38f4d","test_data/tokenizer/success/float_scientific_pos.nix":"9478eb9d68e3e507ab1f25f720a1c989f2e77902444177dd6aca4232ecaa5ec5","test_data/tokenizer/success/float_scientific_upper.expect":"3e4168f2930467478839baeca2e7c8237c031c61437dbfd0ea842c943e383bc1","test_data/tokenizer/success/float_scientific_upper.nix":"90026b760c7133581f71589a8c80388ddb57f448c95926dc20e8343942f8cd86","test_data/tokenizer/success/int.expect":"28f4e978e11a8fe402733032f14d746aa4968051bd82126eefaf7eb924f97ae8","test_data/tokenizer/success/int.nix":"084c799cd551dd1d8d5c5f9a5d593b2e931f5e36122ee5c793c1d08a19839cc0","test_data/tokenizer/success/lambda.expect":"8d8cc573e1dea67f443bb49600600dbf9e34d4139da09d95200abeb76aa28f1b","test_data/tokenizer/success/lambda.nix":"edc937e71d82484ce34a187600422dce3cdbbad0c353da35147f8d6f2994f0e2","test_data/tokenizer/success/lambda_arg_underscore.expect":"40b9e9641d3f66283b3f5997539c879e042a58685108b36b2f0b3020f1f35f64","test_data/tokenizer/success/lambda_arg_underscore.nix":"228cef05debcc896b2a7fae7208405c07fd4ce4e49637aadd06a13a0aa08c9ad","test_data/tokenizer/success/leading_zero_edge_case_01.expect":"abe0c62796f1b8a1cc78edd6709e2e85069bff33466e3b656c736ec885f22ba8","test_data/tokenizer/success/leading_zero_edge_case_01.nix":"1bd1b6fb63ba3bb8ada269699891c2ea83778c4f2cc3fe996578872ec10c8bd6","test_data/tokenizer/success/leading_zero_edge_case_02.expect":"caa387e4263cab5f5394f6435b7ac6d25b3ef8855d0d5db31e4259240c643b09","test_data/tokenizer/success/leading_zero_edge_case_02.nix":"178a93935af6b37ba77d1a5d5c99fd74bba65bd5c2362024af32cfe0d52d2855","test_data/tokenizer/success/leading_zero_numbers.expect":"a5bfde1c19ff74da4b8803b88640536fb5c18ff39c49d3c341c7a13392f4a68b","test_data/tokenizer/success/leading_zero_numbers.nix":"1a4a9dfd1363077fbefb9a532df1691722e3b0bb385aa7d9fc798987a8a1bf24","test_data/tokenizer/success/let.expect":"a267e9ff978d0f6a62a09724a2119bc5628673610e2afd77bff1fa31da8ace3d","test_data/tokenizer/success/let.nix":"1803ee3b3700db15a2c7678914f08c35b4e328b44bbd86784619c1e18bb9b0fe","test_data/tokenizer/success/list.expect":"85d5cfc3c92436999e9a3c2940277f09bd9247b8f2d3202532ce9294cd4037d7","test_data/tokenizer/success/list.nix":"a1314bae234981d632535abc8f7bf00210aac67ea5e49b5c6252ecd963c75d19","test_data/tokenizer/success/list_concat.expect":"e49a50f0657f094e0d7c0f1e0727a30d6281386c3e91bd7a1e338e3d56b9cb54","test_data/tokenizer/success/list_concat.nix":"077c3a36bc5e8a02bd9df0d4ae575f2d1a2553efe87531c29b7769cc02a292b7","test_data/tokenizer/success/math.expect":"a1f48b49f7131fe46f52f1ba1edfec698a966d58a3b728f2e22354a914a10e7e","test_data/tokenizer/success/math.nix":"143a57d9bf045dfc658a42d9d14e9acbc70d39f20b6f9e30a25258066dfea1f3","test_data/tokenizer/success/math_div_isnt_path.expect":"18dae06715fd54fcd46d29f7fb0271b858b5f3a177229e28ec1855256cbd3f13","test_data/tokenizer/success/math_div_isnt_path.nix":"d81aff127813a35217fa9c105ff7f90b2798d58cfad3720066dc45c465758232","test_data/tokenizer/success/math_no_ws.expect":"468e234d13a28a45ba4e99c4fe9ef24a355e4b43bf3e59487d3f0c594ab947f8","test_data/tokenizer/success/math_no_ws.nix":"bbf1bee1b75930cd72023c8f1ec6080cb9aacd408a0a309ceb0df6f6a837d6f6","test_data/tokenizer/success/op_geq_isnt_path.expect":"2706922e527b54a9f02971952bbc4f3b8c4d9544d325c91c844ef17b6651f6d6","test_data/tokenizer/success/op_geq_isnt_path.nix":"573c96bb833e4492c251f82edfdd8715085a6001842eda82d21b3ac8740daa2f","test_data/tokenizer/success/op_update.expect":"b4201923a2d44234079216857a1a192557839876125f04924c6ba0a94f3393e9","test_data/tokenizer/success/op_update.nix":"c2f8e5577834ddc74ffbee478840f64a7868dc0a72c481e7937c23cea8a1ca8e","test_data/tokenizer/success/path_abs_interp_start.expect":"49b9dee7d1c93b7515706a7ff28cb975c848d2441bafb2679b87ed82bed0999f","test_data/tokenizer/success/path_abs_interp_start.nix":"ece1c4989571cc0ce1aec1ff66843082bc8135435a5e60d4cc27cb2423019e75","test_data/tokenizer/success/path_abs_interp_start_suffix.expect":"fcc2508161fd1ea8a79c9391595745e431686b6f1d9a8b8946ee3fc50b2321ba","test_data/tokenizer/success/path_abs_interp_start_suffix.nix":"384d80c11436eff7f2d4641db7e04f07f8e516388c90faf570c6c0e60834129b","test_data/tokenizer/success/path_abs_nix_store.expect":"9accfda5ec93e73b19db8bbb1443a46ddf97cb98de9f0df0442279a5e3e2d06d","test_data/tokenizer/success/path_abs_nix_store.nix":"bf4221009702e333ff32c409db14f5b6c484a4655f70e5f3e651c098b4f80440","test_data/tokenizer/success/path_absolute.expect":"b8cef284d1c3beba06fb95253b22577316015856bdc2e3c6a29a273ae0a739ae","test_data/tokenizer/success/path_absolute.nix":"3a5c5c9243d2ed4a21afae5edd06a075d68fd8468e36a205ad79e67d3d51c1c7","test_data/tokenizer/success/path_home.expect":"5fbf5a8a2c25d88a5886ccb55aa0d80a78647766ee13f37a6296ced8df19f91d","test_data/tokenizer/success/path_home.nix":"d18dd7e377c0858a9c22560b8ee6cc110f11155502159b81d61fc7bcaaef8a93","test_data/tokenizer/success/path_home_hidden.expect":"a013377624e69a6f722057869f82afbb50768c5d478fb307f1c04a206a35a932","test_data/tokenizer/success/path_home_hidden.nix":"e2ea5578890b8e0443d67416892a37dd02b5b7a43482e802169e10a0f4d62106","test_data/tokenizer/success/path_interp.expect":"c586a46abdddbf5b6aff90898e70671a8aa2c712bc7d376402b45118600948f4","test_data/tokenizer/success/path_interp.nix":"7ddc90123195674767eb117ba05ebc7a944ec9c3e6686bb4d4f347c9ad568f07","test_data/tokenizer/success/path_interp_apply.expect":"eeebb13fcd1efeea63f5b490092ca55ca33b61150fa33950b17d25551fb7abf1","test_data/tokenizer/success/path_interp_apply.nix":"fcb2621abe398e700e00639c0da5ab8fc7ad43ef5d08d2220d625a2e642aad25","test_data/tokenizer/success/path_interp_multiple.expect":"775abcd6f6d4715e5888b2cafcdb9158635d2f21494de18e69db700daa87bbcd","test_data/tokenizer/success/path_interp_multiple.nix":"b1ff8d7ea59465d36d1aae1c7f3595e788b96d7796e8e626ebb5b1741f089e1b","test_data/tokenizer/success/path_interp_multiple2.expect":"c413b3a08d8100129f0292042c52fd18090dddb4e8dfe56ec84944bae651b7b2","test_data/tokenizer/success/path_interp_multiple2.nix":"68ff4c036af349bb140aef04d2898dfe0aa52ed17251330a09893c96fa808daa","test_data/tokenizer/success/path_interp_then_plain.expect":"d8d0f337e7bb7b22aeb1f612ec756949627d8d67600a1b0292c6d4fdaf8a0fb1","test_data/tokenizer/success/path_interp_then_plain.nix":"e0550aa1ead3436c9a575391c221e844e6923727794a945bf57a7b5c34cdba78","test_data/tokenizer/success/path_isnt_math.expect":"e2e49d3965950f894d5a57faf8bc2b41f8401838dd218d28e74edc1dfc46faa9","test_data/tokenizer/success/path_isnt_math.nix":"3653a40bab22bda91b7293086c3bf7bf5232a547a2dea0e941ac7f22dafe6ba8","test_data/tokenizer/success/path_no_newline.expect":"df2587079992b6545baeda05da903ce4c938ef16d04c39cd96ed849b13f1a7ef","test_data/tokenizer/success/path_no_newline.nix":"fbd3deff9ff62107cc0c5a05abed01ef17b7e03ccbc2aaed70c80d46370ada7b","test_data/tokenizer/success/path_operators_mix.expect":"18f71482ea28df2206c0e0231b5730c2a00733dd53c42b6def939ec0cf9e23bc","test_data/tokenizer/success/path_operators_mix.nix":"49075fc66ef5b37050543efdaa181c40d37fc5cab7d9eebedd5e4b0f440e8704","test_data/tokenizer/success/path_relative.expect":"edc18b628db41bf2f78a8cd2b69b7cf45ff88c674552485efa2bb50cc1b5a9c0","test_data/tokenizer/success/path_relative.nix":"792919a22b68d7ee3880716670fc67582125a6d5ec6daa8aebaa47fc4847c9d4","test_data/tokenizer/success/path_relative_complex.expect":"6e8fbda7d5d8579da31db97e59d686570a490c730578c583237fd8ea34afea27","test_data/tokenizer/success/path_relative_complex.nix":"7fa7e698d6d9e202000f2ba940828ce52351a9d27a04e9f6ccea37c78b0443e8","test_data/tokenizer/success/path_relative_prefix.expect":"442d1ef6215e280547de44f251b26903cfb9d2eb255ec19989df81b1de8f7d97","test_data/tokenizer/success/path_relative_prefix.nix":"62988baa99d8acb144e3015df3797b7fe78f998665b34005fcef26856d3213d6","test_data/tokenizer/success/path_search_complex.expect":"64ec5355d02297b2fb0b3782d75bd8abfd5355617dcabf371f44644287c56735","test_data/tokenizer/success/path_search_complex.nix":"73fac0237c9f4fc09834623c1847aaf4d0d2a7af6916f7caa71460b6399d290a","test_data/tokenizer/success/path_search_with_dash.expect":"a790fea183049d65658d9f2753ecc9e2c83f056e9be011df48a21db405bb348e","test_data/tokenizer/success/path_search_with_dash.nix":"a3971a9bcd91abadd19235201b9b975e2d8d281bf028adf93672d998433dfce8","test_data/tokenizer/success/path_store.expect":"fbcd777ec6e3fdcf4462898c4a2bc14f4d9157064691d6a257876bb42b378d7b","test_data/tokenizer/success/path_store.nix":"befc8124e719179fe79ae5463db8a986a6217eca60924f772ed6c0964588ce60","test_data/tokenizer/success/path_underscore.expect":"1b492881108d42c3d49245a0665d4b835f9f0c6aed0663ffe9efb1aa2ce9a83d","test_data/tokenizer/success/path_underscore.nix":"194767da1ecb24b9335af8d818af6cc84773b175fa776f72a0bf0d510c5c1332","test_data/tokenizer/success/path_with_numbers.expect":"b6d6658723600e66abc3a0f7155081ab2f5242d12ffb1c457485397b7002cb1e","test_data/tokenizer/success/path_with_numbers.nix":"1f2645b56cffde46fc8aa7a840c09092ca0c2587911fa4234e2e0b7fded8d734","test_data/tokenizer/success/path_with_plus.expect":"8b486e350bdbac033dc1a52e655264c3907adb93cfe1ee3bc9e9e61a467b6180","test_data/tokenizer/success/path_with_plus.nix":"b839da45769ea289302782a32c265f10ded9dfc34438542a101461f2f195cc8f","test_data/tokenizer/success/patterns.expect":"b20ff13495b2d39dc52bb5185ef2e450a81ff98e963e2c0f12ab50f24912d40d","test_data/tokenizer/success/patterns.nix":"92f54b1c561bd2854647e31688ebf225571db65baaaa2c1e18b78f2da77d8b01","test_data/tokenizer/success/select_dynamic.expect":"6e9d17d78d38411950228b4d68dd096fcf3de66279bf4a10b418e3e8cadd2c5b","test_data/tokenizer/success/select_dynamic.nix":"4e422abdcb8b545b7bf94ed7cb9499c668169e9853486d84c08707cb1d60122e","test_data/tokenizer/success/string.expect":"a400c9c33cf7c412aade13539b1afbc79c027b97f2d82c082dce9718fe95f565","test_data/tokenizer/success/string.nix":"b58f34e73579dcfb700daacadd50fa7503f1e4c6c881cb4d720fe84a57be306d","test_data/tokenizer/success/string_dollar_escape.expect":"7ed077e0f375e8f1ef2554246a42d76c44fad12273b68e1c9f44cbeb4db10996","test_data/tokenizer/success/string_dollar_escape.nix":"6dfd70ebec2a52a2366aea07ab5210b07f21334be4205232e24c3948b56e9751","test_data/tokenizer/success/string_escape.expect":"16b19f9fad85f5eb8ec64f61c7fa46032dc183b129ce892c2aa192a70fbe9d34","test_data/tokenizer/success/string_escape.nix":"3fee5dbf0405cac9f27e1f4cf8785312b5b3e3e8d169e1d04c5d9d47c78239cf","test_data/tokenizer/success/string_interp.expect":"bba28281da8d137ec632375e45f9efe2c8a2d387418449515c9099e228949e6d","test_data/tokenizer/success/string_interp.nix":"810765384a00c3c779fdb7a0fe76c8461a825da3690bcb0cb20b3c404e9f7855","test_data/tokenizer/success/string_interp_dollar_escape.expect":"49a2ad75edcbdbe7891da51bcc93d841a834be5e8c35b98ec28062c695d44abd","test_data/tokenizer/success/string_interp_dollar_escape.nix":"ac4778cc4b130b75774be9ac6a93cac222ff63d5e5983ac37803cef0943db8cd","test_data/tokenizer/success/string_interp_nested.expect":"5213c0e121a13a6fea32eef6c3b61b55e07681018e0a3affd6dccc1b1237d8b6","test_data/tokenizer/success/string_interp_nested.nix":"35c6ad254ec867901815eb6a8980ef3a118764e76d2e1ba3ab4270f96a9fd4a7","test_data/tokenizer/success/string_interp_select.expect":"cdb4668d9c34f9c389e048e5a9221eb86a0483a6f43692c6ac03817731c48e78","test_data/tokenizer/success/string_interp_select.nix":"434bc66e29d42a5b27f67fb14d0fe35e96ab035cf94299756a79d49201bd5eeb","test_data/tokenizer/success/string_isnt_path.expect":"781a0d90853ed0b5c69c739731f286e316dc5069cadc359d3c34f9c093a7c105","test_data/tokenizer/success/string_isnt_path.nix":"da46b217d9aeb3142d8d68f8b2d23506ff7d4d55033851abf578d816e3ef5fb9","test_data/tokenizer/success/string_multiline.expect":"58823b6b8979a268a4cde97eb678504c95236b37c461f1b97fa7067d9f75e440","test_data/tokenizer/success/string_multiline.nix":"85824e261725ef072ed13d1adbb77c9bc1c6658a9f40da316aadd3c810c91191","test_data/tokenizer/success/string_multiline_dollar_escape.expect":"79fa6bdf36132023d972d0840bbc5d6c78501e5e59647e56955854d3e6346720","test_data/tokenizer/success/string_multiline_dollar_escape.nix":"f375a511e2f9c7a05594569e9f0b67c3c00e7e0263018cef5268e1065219fa9e","test_data/tokenizer/success/string_multiline_interp_escape.expect":"cb90867f2a0538f21a5b974059f65f92554655c1efb4e0be1d238e32922bd4fa","test_data/tokenizer/success/string_multiline_interp_escape.nix":"d22ba88c49e8a8798f5a86f65a526fd3fdb9114978b4bc331af366932612fc8d","test_data/tokenizer/success/uri.expect":"42f98b5e5c5abee09d8da7d7b6ffdd8175a0bb4c4971b72c46b971ba82b569aa","test_data/tokenizer/success/uri.nix":"fd6c53b543f835753a4715918ea33a250b132ab516c334dc79c589c7a9dbd1a2","test_data/tokenizer/success/uri_git_ssh.expect":"820ac15a964e6e16430d0966d46083c5ca5149e84a5ebddac954c5974e39748c","test_data/tokenizer/success/uri_git_ssh.nix":"b57b00d82eb3cdf4156d43e2a055947bb668127f94b104c1c084d24b5d22eb19","test_data/tokenizer/success/uri_https.expect":"7aa7f28f6b33158affea4ee36295cd58b55dcebfa484d845d9efca3f4cdab72c","test_data/tokenizer/success/uri_https.nix":"4ad0c60c2098b26aa22a48e3f5e3ce2824254f33788108cf15dee2c9546f5f32","test_data/tokenizer/success/uri_with_underscore.expect":"f9626c92585c934152b96498d196a36628f5fe2461a9fa09b3d1d363912d7595","test_data/tokenizer/success/uri_with_underscore.nix":"27b4217b01af5c24748229732a9155d9c612257de8a2e183aebfd602ebe53ede","test_data/tokenizer/success/with.expect":"55439e02492ea9248fe37c77e2e4de34f34fe64917fa99bef90124365d30837e","test_data/tokenizer/success/with.nix":"751963ece23baa99102bbbf61126f5228b525bcbdc7c8b0719efc6e4d0cf15c0"},"package":"c163bd17372eecdf10d351c34584b7de7c1a33be4e92a32f3fb3f5a7fe3f579b"} \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/.cargo_vcs_info.json b/third_party/crates/rnix-0.14.0/.cargo_vcs_info.json new file mode 100644 index 0000000..2652cfd --- /dev/null +++ b/third_party/crates/rnix-0.14.0/.cargo_vcs_info.json @@ -0,0 +1,7 @@ +{ + "git": { + "sha1": "0472081214c24b1ab4d34f7bf544284ed4e45ad3", + "dirty": true + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/bug_report.md b/third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..53d49dd --- /dev/null +++ b/third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,36 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: 'bug' +assignees: '' +--- + + + +### Describe the bug + + + +### Code Snippet to reproduce + + + +```nix + +``` + +### Expected behavior + + + +### Additional context + + + diff --git a/third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/feature_request.md b/third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..5b9cb5c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,29 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' +--- + + + +### Description + + + +### Considered alternatives + + + +### Additional context + + diff --git a/third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/question.md b/third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..3f9ac3d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,7 @@ +--- +name: Question +about: Ask a general question about the project +title: '' +labels: 'question' +assignees: '' +--- diff --git a/third_party/crates/rnix-0.14.0/.github/PULL_REQUEST_TEMPLATE.md b/third_party/crates/rnix-0.14.0/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..d6ed682 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,25 @@ + + + +### Summary & Motivation + + + +### Backwards-incompatible changes + + + +### Further context + + diff --git a/third_party/crates/rnix-0.14.0/.github/dependabot.yml b/third_party/crates/rnix-0.14.0/.github/dependabot.yml new file mode 100644 index 0000000..5ace460 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" diff --git a/third_party/crates/rnix-0.14.0/.github/workflows/ci.yml b/third_party/crates/rnix-0.14.0/.github/workflows/ci.yml new file mode 100644 index 0000000..f93845d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/.github/workflows/ci.yml @@ -0,0 +1,64 @@ +name: ci +on: + pull_request: + push: + branches: + - master + +jobs: + test: + name: test + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - macos-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Cache Dependencies + uses: Swatinem/rust-cache@v2 + + - name: Compile + run: cargo test --no-run --locked + + - name: Test + run: cargo test -- --nocapture + + rustfmt: + name: rustfmt + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + + - name: Check formatting + run: cargo fmt --all -- --check + + clippy: + name: clippy + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - name: Run Clippy + run: cargo clippy diff --git a/third_party/crates/rnix-0.14.0/BUILD.bazel b/third_party/crates/rnix-0.14.0/BUILD.bazel new file mode 100644 index 0000000..a4a543a --- /dev/null +++ b/third_party/crates/rnix-0.14.0/BUILD.bazel @@ -0,0 +1,113 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "rnix", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=rnix", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "0.14.0", + deps = [ + "//third_party/crates/rowan-0.16.1:rowan", + ], +) diff --git a/third_party/crates/rnix-0.14.0/CHANGELOG.md b/third_party/crates/rnix-0.14.0/CHANGELOG.md new file mode 100644 index 0000000..1060b81 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/CHANGELOG.md @@ -0,0 +1,190 @@ +# Changelog + +All notable changes between releases will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [Unreleased] + +## [v0.14.0] - 2026-02-16 + +### Fixed + +* Fix absolute path interpolation starting with `/${` failing to parse + ([#182](https://github.com/nix-community/rnix-parser/issues/182), + from [@imxyy1soope1](https://github.com/imxyy1soope1)). + +### Breaking Changes + +* **`__curPos` is now a distinct node type.** `__curPos` is a Nix keyword that evaluates to an + attribute set containing the file, line, and column where it appears. + [Lix documents this as a keyword.](https://docs.lix.systems/manual/lix/nightly/language/constructs.html#keywords-__curPos) + It was previously represented as `NODE_IDENT`, but is now parsed as `NODE_CUR_POS` with a + corresponding `TOKEN_CUR_POS` token kind (from [@3timeslazy](https://github.com/3timeslazy)). + +## [v0.13.0] - 2026-01-29 + +### Breaking Changes + +* **Path types are now distinguished at the type level.** `TOKEN_PATH` and `NODE_PATH` have been + replaced with specific variants for each path type: + - `TOKEN_PATH_ABS` / `NODE_PATH_ABS` - absolute paths (`/foo/bar`) + - `TOKEN_PATH_REL` / `NODE_PATH_REL` - relative paths (`./foo`, `../bar`, `foo/bar`) + - `TOKEN_PATH_HOME` / `NODE_PATH_HOME` - home-relative paths (`~/foo`) + - `TOKEN_PATH_SEARCH` / `NODE_PATH_SEARCH` - search paths (``) + + The `ast::Expr` enum now has `PathAbs`, `PathRel`, `PathHome`, and `PathSearch` variants + instead of a single `Path` variant. See `MIGRATING.md` for upgrade guidance. + +* **Double slashes in paths are now syntax errors.** Paths like `foo//bar` now produce + `TOKEN_ERROR` instead of being parsed. + +* **The `parser` and `tokenizer` modules are now private.** Use `rnix::Root::parse()` and + `rnix::tokenize()` instead. + +### Added + +* Implement `FromStr` for `SyntaxKind` (from [@abhillman](https://github.com/abhillman)). + +* Add `MIGRATING.md` with upgrade guidance for breaking changes. + +* Add `nix develop .#fuzz` devShell for running cargo-fuzz with nightly Rust. + +### Fixed + +* Fix leading zero number parsing to match Nix behavior (from [@hsjobeki](https://github.com/hsjobeki)). + +### Changed + +* Update `rowan` to 0.16. +* Update `criterion` to 0.8. +* Update `expect-test` to 1.5.1. +* Add Clippy to CI and resolve all warnings. + +## [v0.12.0] - 2025-01-09 + +* Add support for pipe operators + +## [v0.11.0] - 2022-11-11 + +* removes the `types` module and replaces it with `ast` + +* the `ast` modules has better types and sum types + +* removes `ParsedType` in favor of `Expr` + +* removes the `value` module. methods on `Value` go on the individual types. For example, string related methods go on `ast::Str` + +* `parse` changed to `Root::parse` + +* `NODE_OR_DEFAULT` is removed + +* `NODE_KEY` -> `NODE_ATTRPATH`, `NODE_KEY_VALUE` -> `NODE_ATTRPATH_VALUE` + +* `BinOp::IsSet` is removed since it's actually not a normal binary operator. + +* `NODE_SELECT` is flattened in favor of `NODE_ATTRPATH` which consists of multiple Attrs, including `a.b.c` and `a.b.c or expr` + +* `a or b` is Apply, not "OrDefault", which matches the result of Nix. Fixes #23 + +* `${` is considered invalid at Expr places now, which matches the result of Nix. + +* remove `TOKEN_DYNAMIC_START` and `TOKEN_DYNAMIC_END` + +* rowan 15.0 + +* various other parsing fixes + +## [v0.10.2] - 2022-06-14 + +* Correctly parse every possible case of path-interpolation in Nix code ([#85](https://github.com/nix-community/rnix-parser/issues/85)). + + (from [@ncfavier](https://github.com/ncfavier)). + +## [v0.10.1] - 2021-12-06 + +### Fixed + +* Trivia tokens (i.e. ` `, `\r`, `\n` etc.) are no longer misplaced around path-expressions. + This is a regression from `v0.10.0` which would've broken `nixpkgs-fmt`. + + (from [@Ma27](https://github.com/Ma27)). + +## [v0.10.0] - 2021-11-30 + +### Added + +* Support for the new path-interpolation syntax from Nix 2.4 was added. The parser + now correctly detects + + ```nix + ./foo/${bar} + ``` + + as valid code and parses it down to + + ``` + NODE_ROOT 0..13 { + NODE_PATH_WITH_INTERPOL 0..12 { + TOKEN_PATH("./foo/") 0..6 + NODE_STRING_INTERPOL 6..12 { + TOKEN_INTERPOL_START("${") 6..8 + NODE_IDENT 8..11 { + TOKEN_IDENT("bar") 8..11 + } + TOKEN_INTERPOL_END("}") 11..12 + } + } + TOKEN_WHITESPACE("\n") 12..13 + } + ``` + + Paths without interpolation are still within `NODE_LITERAL` for backwards-compatibility. + + (from [@Ma27](https://github.com/Ma27)). + +* `rnix::types::ParsedTypeError` now implements the `Debug`, `Copy`, `Clone`, `fmt::Display` traits (from [@NerdyPepper](https://github.com/NerdyPepper)). + +* During development, the parser can be tested like this: + + ``` + $ cargo run --example from-stdin <<< 'builtins.map (x: x * x) [ 1 2 3 ]' + ``` + + (from [@efx](https://github.com/efx)). + +### Changed + +* A few more examples of invalid `inherit`-expressions are correctly marked as such (from [@oberblastmeister](https://github.com/oberblastmeister)). + +* `rnix::types::BinOp::operator()` now returns `Option` rather than unwrapping the + value (from [@NerdyPepper](https://github.com/NerdyPepper)). + + If your code worked fine before, it will be sufficient to add a `.unwrap()` since this was + what happened before within `::operator()`. + +* Duplicated arguments in the argument-pattern syntax are now marked as parser error. E.g. + + ```nix + { a, a }: a + ``` + + now produces an error (from [@Ma27](https://github.com/Ma27)). + +* Floats without trailing zeroes (e.g. `.5`) are no longer marked as syntax error (from [@Ma27](https://github.com/Ma27)). + +## [v0.9.1] - 2021-09-23 + +### Changed + +* Fixed a memory leak while parsing `inherit`-expressions with invalid syntax (from [@Ma27](https://github.com/Ma27/)). + +[Unreleased]: https://github.com/nix-community/rnix-parser/compare/v0.14.0...master +[v0.14.0]: https://github.com/nix-community/rnix-parser/compare/v0.13.0...v0.14.0 +[v0.13.0]: https://github.com/nix-community/rnix-parser/compare/v0.12.0...v0.13.0 +[v0.12.0]: https://github.com/nix-community/rnix-parser/compare/v0.11.0...v0.12.0 +[v0.11.0]: https://github.com/nix-community/rnix-parser/compare/v0.10.2...v0.11.0 +[v0.10.2]: https://github.com/nix-community/rnix-parser/compare/v0.10.1...v0.10.2 +[v0.10.1]: https://github.com/nix-community/rnix-parser/compare/v0.10.0...v0.10.1 +[v0.10.0]: https://github.com/nix-community/rnix-parser/compare/v0.9.1...v0.10.0 +[v0.9.1]: https://github.com/nix-community/rnix-parser/compare/v0.9.0...v0.9.1 diff --git a/third_party/crates/rnix-0.14.0/Cargo.lock b/third_party/crates/rnix-0.14.0/Cargo.lock new file mode 100644 index 0000000..2a11cc1 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/Cargo.lock @@ -0,0 +1,660 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e34525d5bbbd55da2bb745d34b36121baac88d07619a9a09cfcf4a6c0832785" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a20016a20a3da95bef50ec7238dbd09baeef4311dcdd38ec15aba69812fb61" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" + +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + +[[package]] +name = "criterion" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d883447757bb0ee46f233e9dc22eb84d93a9508c9b868687b274fc431d886bf" +dependencies = [ + "alloca", + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "num-traits", + "oorandom", + "page_size", + "plotters", + "rayon", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed943f81ea2faa8dcecbbfa50164acf95d555afec96a27871663b300e387b2e4" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "dissimilar" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "expect-test" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0" +dependencies = [ + "dissimilar", + "once_cell", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rnix" +version = "0.14.0" +dependencies = [ + "criterion", + "expect-test", + "rowan", +] + +[[package]] +name = "rowan" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21" +dependencies = [ + "countme", + "hashbrown", + "rustc-hash", + "text-size", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "text-size" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "zerocopy" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" diff --git a/third_party/crates/rnix-0.14.0/Cargo.toml b/third_party/crates/rnix-0.14.0/Cargo.toml new file mode 100644 index 0000000..26c8e58 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/Cargo.toml @@ -0,0 +1,68 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "rnix" +version = "0.14.0" +authors = ["jD91mZM2 "] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A Nix parser written in Rust" +readme = "README.md" +license = "MIT" +repository = "https://github.com/nix-community/rnix-parser" + +[lib] +name = "rnix" +path = "src/lib.rs" + +[[example]] +name = "dump-ast" +path = "examples/dump-ast.rs" + +[[example]] +name = "error-report" +path = "examples/error-report.rs" + +[[example]] +name = "from-stdin" +path = "examples/from-stdin.rs" + +[[example]] +name = "list-fns" +path = "examples/list-fns.rs" + +[[example]] +name = "preserve" +path = "examples/preserve.rs" + +[[example]] +name = "test-nixpkgs" +path = "examples/test-nixpkgs.rs" + +[[bench]] +name = "all-packages" +path = "benches/all-packages.rs" +harness = false + +[dependencies.rowan] +version = "0.16" + +[dev-dependencies.criterion] +version = "0.8" + +[dev-dependencies.expect-test] +version = "1.5.1" diff --git a/third_party/crates/rnix-0.14.0/Cargo.toml.orig b/third_party/crates/rnix-0.14.0/Cargo.toml.orig new file mode 100644 index 0000000..7f1f9ad --- /dev/null +++ b/third_party/crates/rnix-0.14.0/Cargo.toml.orig @@ -0,0 +1,20 @@ +[package] +authors = ["jD91mZM2 "] +description = "A Nix parser written in Rust" +edition = "2021" +license = "MIT" +name = "rnix" +readme = "README.md" +repository = "https://github.com/nix-community/rnix-parser" +version = "0.14.0" + +[[bench]] +harness = false +name = "all-packages" + +[dependencies] +rowan = "0.16" + +[dev-dependencies] +criterion = "0.8" +expect-test = "1.5.1" diff --git a/third_party/crates/rnix-0.14.0/LICENSE b/third_party/crates/rnix-0.14.0/LICENSE new file mode 100644 index 0000000..018ac6f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 jD91mZM2 + +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/third_party/crates/rnix-0.14.0/MIGRATING.md b/third_party/crates/rnix-0.14.0/MIGRATING.md new file mode 100644 index 0000000..e412355 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/MIGRATING.md @@ -0,0 +1,104 @@ +# Migration Guide + +## Migrating to 0.13.0 + +### Path types are now distinguished at the type level + +Previously, all Nix paths were parsed into a single `TOKEN_PATH` / `NODE_PATH` type, requiring runtime string inspection to determine the path variant. Now, paths are distinguished at the type level: + +| Path Type | Example | Token | Node | +|-----------|---------|-------|------| +| Absolute | `/foo/bar` | `TOKEN_PATH_ABS` | `NODE_PATH_ABS` | +| Relative | `./foo`, `../bar`, `foo/bar` | `TOKEN_PATH_REL` | `NODE_PATH_REL` | +| Home-relative | `~/foo` | `TOKEN_PATH_HOME` | `NODE_PATH_HOME` | +| Search | `` | `TOKEN_PATH_SEARCH` | `NODE_PATH_SEARCH` | + +#### Updating `SyntaxKind` matches + +```rust +// Before: +match kind { + SyntaxKind::TOKEN_PATH => { /* ... */ } + SyntaxKind::NODE_PATH => { /* ... */ } +} + +// After: +match kind { + SyntaxKind::TOKEN_PATH_ABS + | SyntaxKind::TOKEN_PATH_REL + | SyntaxKind::TOKEN_PATH_HOME + | SyntaxKind::TOKEN_PATH_SEARCH => { /* ... */ } + + SyntaxKind::NODE_PATH_ABS + | SyntaxKind::NODE_PATH_REL + | SyntaxKind::NODE_PATH_HOME + | SyntaxKind::NODE_PATH_SEARCH => { /* ... */ } +} +``` + +#### Updating `Expr` matches + +The `Expr` enum no longer has a `Path` variant. Instead, there are four separate variants: + +```rust +// Before: +match expr { + ast::Expr::Path(p) => { + // Had to inspect the string to determine path type + } + // ... +} + +// After: +match expr { + ast::Expr::PathAbs(p) => { /* absolute path like /foo/bar */ } + ast::Expr::PathRel(p) => { /* relative path like ./foo */ } + ast::Expr::PathHome(p) => { /* home path like ~/foo */ } + ast::Expr::PathSearch(p) => { /* search path like */ } + // ... +} +``` + +#### Using the `Path` enum + +If you need to handle all path types uniformly, use the `ast::Path` enum: + +```rust +use rnix::ast::{AstNode, Path}; + +// Cast any path node to the Path enum +if let Some(path) = Path::cast(node) { + match path { + Path::PathAbs(p) => { /* ... */ } + Path::PathRel(p) => { /* ... */ } + Path::PathHome(p) => { /* ... */ } + Path::PathSearch(p) => { /* ... */ } + } + + // Or use helper methods + if path.is_search() { + // Search paths don't support interpolation + } + + // Get parts from any path type + let parts = path.parts(); +} +``` + +#### `Path::parts()` return type change + +The `parts()` method now returns `Vec>` instead of `impl Iterator<...>`: + +```rust +// Before: +let mut parts = path.parts(); +let first = parts.next(); + +// After: +let parts = path.parts(); +let first = parts.first(); +``` + +### Double slashes in paths are now syntax errors + +Paths containing `//` (e.g., `foo//bar`) are now tokenized as `TOKEN_ERROR`. This matches Nix's behavior where such paths are invalid. diff --git a/third_party/crates/rnix-0.14.0/README.md b/third_party/crates/rnix-0.14.0/README.md new file mode 100644 index 0000000..acd8fcf --- /dev/null +++ b/third_party/crates/rnix-0.14.0/README.md @@ -0,0 +1,88 @@ +# rnix-parser [![Crates.io](https://img.shields.io/crates/v/rnix.svg)](http://crates.io/crates/rnix) [![Chat on Matrix](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#rnix-lsp:matrix.org) + +rnix is a parser for the [Nix language](https://nixos.org/nix/) written in Rust. + +This can be used to manipulate the Nix AST and can for example be used for: + +- Interactively render Nix on a GUI +- Formatting Nix code +- Rename identifiers + +and a lot more! + +rnix nowadays uses [@matklad](https://github.com/matklad)'s +[rowan](https://crates.io/crates/rowan) crate to ensure: + +- all span information is preserved, meaning you can use the AST to for + example apply highlighting +- printing out the AST prints out 100% the original code. This is not an + over-exaggeration, even completely invalid nix code such as this README can + be intact after a parsing session (though the AST will mark errnous nodes) +- easy ways to walk the tree without resorting to recursion + +## Demo + +Examples can be found in the `examples/` directory. + +You may also want to see +[nix-explorer](https://gitlab.com/jD91mZM2/nix-explorer): An example +that highlights AST nodes in Nix code. This demonstrates how +whitespaces and commands are preserved. + +## Hacking + +Tests can be run with `cargo test`. + +In order to update all `.expect`-files to the currently expected results, +you may run `UPDATE_TESTS=1 cargo test`. + +You can parse Nix expressions from standard input using the `from-stdin` example. +To try that, run the following in your shell: + +```sh +echo "[hello nix]" | cargo run --quiet --example from-stdin +``` + +## Release Checklist + +* Ensure that all PRs that were scheduled for the release are merged (or optionally move + them to another milestone). +* Close the milestone for the release (if any). +* Run `cargo test` on `master` (or the branch to release from) with all changes being pulled in. +* Apply the following patch to [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt): + ```diff + diff --git a/Cargo.toml b/Cargo.toml + index 0891350..edad471 100644 + --- a/Cargo.toml + +++ b/Cargo.toml + @@ -13,6 +13,9 @@ repository = "https://github.com/nix-community/nixpkgs-fmt" + [workspace] + members = [ "./wasm" ] + + +[patch.crates-io] + +rnix = { path = "/home/ma27/Projects/rnix-parser" } + + + [dependencies] + rnix = "0.9.0" + smol_str = "0.1.17" + ``` + + and run `cargo test`. + + While it's planned to add [fuzzing to `rnix-parser` as well](https://github.com/nix-community/rnix-parser/issues/32), + `nixpkgs-fmt` has a decent test-suite that would've helped to catch regressions in the past. + + __Note:__ API changes are OK (and fixes should be contributed to `nixpkgs-fmt`), behavioral changes + are not unless explicitly discussed before. +* Update the [CHANGELOG.md](https://github.com/nix-community/rnix-parser/blob/master/CHANGELOG.md). +* Bump the version number in [Cargo.toml](https://github.com/nix-community/rnix-parser/blob/master/Cargo.toml) & re-run `cargo build` to refresh the lockfile. +* Commit & run `nix build`. +* Tag the release and push everything. +* As soon as the CI has completed, run `cargo publish`. + +# RIP jd91mzm2 + +Sadly, the original author of this project, [@jD91mZM2 has passed +away](https://www.redox-os.org/news/open-source-mental-health/). His online +presence was anonymous and what we have left is his code. This is but one of +his many repos that he contributed to. diff --git a/third_party/crates/rnix-0.14.0/benches/all-packages.nix b/third_party/crates/rnix-0.14.0/benches/all-packages.nix new file mode 100644 index 0000000..5ec34da --- /dev/null +++ b/third_party/crates/rnix-0.14.0/benches/all-packages.nix @@ -0,0 +1,24853 @@ +/* The top-level package collection of nixpkgs. + * It is sorted by categories corresponding to the folder names + * in the /pkgs folder. Inside the categories packages are roughly + * sorted by alphabet, but strict sorting has been long lost due + * to merges. Please use the full-text search of your editor. ;) + * Hint: ### starts category names. + */ +{ lib, noSysDirs, config, overlays }: +res: pkgs: super: + +with pkgs; + +let + self = + builtins.trace '' + It seems that you are using a patched Nixpkgs that references the self + variable in pkgs/top-level/all-packages.nix. This variable was incorrectly + named, so its usage needs attention. Please use pkgs for packages or super + for functions. + '' + res; # Do *NOT* use res in your fork. It will be removed. + + # TODO: turn self into an error + +in +{ + + # A stdenv capable of building 32-bit binaries. On x86_64-linux, + # it uses GCC compiled with multilib support; on i686-linux, it's + # just the plain stdenv. + stdenv_32bit = lowPrio (if stdenv.hostPlatform.is32bit then stdenv else multiStdenv); + + stdenvNoCC = stdenv.override { cc = null; extraAttrs.noCC = true; }; + + mkStdenvNoLibs = stdenv: let + bintools = stdenv.cc.bintools.override { + libc = null; + noLibc = true; + }; + in stdenv.override { + cc = stdenv.cc.override { + libc = null; + noLibc = true; + extraPackages = []; + inherit bintools; + }; + allowedRequisites = + lib.mapNullable (rs: rs ++ [ bintools ]) (stdenv.allowedRequisites or null); + }; + + stdenvNoLibs = mkStdenvNoLibs stdenv; + + gccStdenvNoLibs = mkStdenvNoLibs gccStdenv; + clangStdenvNoLibs = mkStdenvNoLibs clangStdenv; + + # For convenience, allow callers to get the path to Nixpkgs. + path = ../..; + + + ### Helper functions. + inherit lib config overlays; + + inherit (lib) lowPrio hiPrio appendToName makeOverridable; + + # Applying this to an attribute set will cause nix-env to look + # inside the set for derivations. + recurseIntoAttrs = attrs: attrs // { recurseForDerivations = true; }; + + # This is intended to be the reverse of recurseIntoAttrs, as it is + # defined now it exists mainly for documentation purposes, but you + # can also override this with recurseIntoAttrs to recurseInto all + # the Attrs which is useful for testing massive changes. Ideally, + # every package subset not marked with recurseIntoAttrs should be + # marked with this. + dontRecurseIntoAttrs = x: x; + + stringsWithDeps = lib.stringsWithDeps; + + ### Evaluating the entire Nixpkgs naively will fail, make failure fast + AAAAAASomeThingsFailToEvaluate = throw '' + Please be informed that this pseudo-package is not the only part of + Nixpkgs that fails to evaluate. You should not evaluate entire Nixpkgs + without some special measures to handle failing packages, like those taken + by Hydra. + ''; + + tests = callPackages ../test {}; + + ### Nixpkgs maintainer tools + + nix-generate-from-cpan = callPackage ../../maintainers/scripts/nix-generate-from-cpan.nix { }; + + nixpkgs-lint = callPackage ../../maintainers/scripts/nixpkgs-lint.nix { }; + + common-updater-scripts = callPackage ../common-updater/scripts.nix { }; + + ### Push NixOS tests inside the fixed point + + nixosTests = import ../../nixos/tests/all-tests.nix { + inherit pkgs; + system = stdenv.hostPlatform.system; + callTest = t: t.test; + }; + + ### BUILD SUPPORT + + autoreconfHook = makeSetupHook + { deps = [ autoconf automake gettext libtool ]; } + ../build-support/setup-hooks/autoreconf.sh; + + autoreconfHook264 = makeSetupHook + { deps = [ autoconf264 automake111x gettext libtool ]; } + ../build-support/setup-hooks/autoreconf.sh; + + autoPatchelfHook = makeSetupHook { name = "auto-patchelf-hook"; } + ../build-support/setup-hooks/auto-patchelf.sh; + + appimageTools = callPackage ../build-support/appimage { }; + + ensureNewerSourcesHook = { year }: makeSetupHook {} + (writeScript "ensure-newer-sources-hook.sh" '' + postUnpackHooks+=(_ensureNewerSources) + _ensureNewerSources() { + '${findutils}/bin/find' "$sourceRoot" \ + '!' -newermt '${year}-01-01' -exec touch -h -d '${year}-01-02' '{}' '+' + } + ''); + + addOpenGLRunpath = callPackage ../build-support/add-opengl-runpath { }; + + avro-tools = callPackage ../development/tools/avro-tools { }; + + # Zip file format only allows times after year 1980, which makes e.g. Python wheel building fail with: + # ValueError: ZIP does not support timestamps before 1980 + ensureNewerSourcesForZipFilesHook = ensureNewerSourcesHook { year = "1980"; }; + + updateAutotoolsGnuConfigScriptsHook = makeSetupHook + { substitutions = { gnu_config = gnu-config;}; } + ../build-support/setup-hooks/update-autotools-gnu-config-scripts.sh; + + gogUnpackHook = makeSetupHook { + name = "gog-unpack-hook"; + deps = [ innoextract file-rename ]; } + ../build-support/setup-hooks/gog-unpack.sh; + + buildEnv = callPackage ../build-support/buildenv { }; # not actually a package + + buildFHSUserEnv = callPackage ../build-support/build-fhs-userenv { }; + + buildMaven = callPackage ../build-support/build-maven.nix {}; + + castget = callPackage ../applications/networking/feedreaders/castget { }; + + castxml = callPackage ../development/tools/castxml { }; + + clj-kondo = callPackage ../development/tools/clj-kondo { }; + + cmark = callPackage ../development/libraries/cmark { }; + + cm256cc = callPackage ../development/libraries/cm256cc { }; + + conftest = callPackage ../development/tools/conftest {}; + + corgi = callPackage ../development/tools/corgi { }; + + dhallToNix = callPackage ../build-support/dhall-to-nix.nix { + inherit dhall-nix; + }; + + deadcode = callPackage ../development/tools/deadcode { }; + + proto-contrib = callPackage ../development/tools/proto-contrib {}; + + protoc-gen-doc = callPackage ../development/tools/protoc-gen-doc {}; + + demoit = callPackage ../servers/demoit { }; + + deviceTree = callPackage ../os-specific/linux/device-tree {}; + + device-tree_rpi = callPackage ../os-specific/linux/device-tree/raspberrypi.nix {}; + + diffPlugins = (callPackage ../build-support/plugins.nix {}).diffPlugins; + + dieHook = makeSetupHook {} ../build-support/setup-hooks/die.sh; + + archiver = callPackage ../applications/misc/archiver { }; + + digitalbitbox = libsForQt5.callPackage ../applications/misc/digitalbitbox { }; + + grsync = callPackage ../applications/misc/grsync { }; + + dockerTools = callPackage ../build-support/docker { }; + + snapTools = callPackage ../build-support/snap { }; + + nix-prefetch-docker = callPackage ../build-support/docker/nix-prefetch-docker.nix { }; + + docker-compose = python3Packages.callPackage ../applications/virtualization/docker-compose {}; + + docker-ls = callPackage ../tools/misc/docker-ls { }; + + docker-sync = callPackage ../tools/misc/docker-sync { }; + + docui = callPackage ../tools/misc/docui { }; + + dotfiles = callPackage ../applications/misc/dotfiles { }; + + dotnetenv = callPackage ../build-support/dotnetenv { + dotnetfx = dotnetfx40; + }; + + dotnetbuildhelpers = callPackage ../build-support/dotnetbuildhelpers { }; + + dotnet-sdk = callPackage ../development/compilers/dotnet/sdk { }; + + dispad = callPackage ../tools/X11/dispad { }; + + dump1090 = callPackage ../applications/radio/dump1090 { }; + + ebook2cw = callPackage ../applications/radio/ebook2cw { }; + + etBook = callPackage ../data/fonts/et-book { }; + + fetchbower = callPackage ../build-support/fetchbower { + inherit (nodePackages) bower2nix; + }; + + fetchbzr = callPackage ../build-support/fetchbzr { }; + + fetchcvs = callPackage ../build-support/fetchcvs { }; + + fetchdarcs = callPackage ../build-support/fetchdarcs { }; + + fetchdocker = callPackage ../build-support/fetchdocker { }; + + fetchDockerConfig = callPackage ../build-support/fetchdocker/fetchDockerConfig.nix { }; + + fetchDockerLayer = callPackage ../build-support/fetchdocker/fetchDockerLayer.nix { }; + + fetchfossil = callPackage ../build-support/fetchfossil { }; + + fetchgit = callPackage ../build-support/fetchgit { + git = buildPackages.gitMinimal; + cacert = buildPackages.cacert; + }; + + fetchgitPrivate = callPackage ../build-support/fetchgit/private.nix { }; + + fetchgitLocal = callPackage ../build-support/fetchgitlocal { }; + + fetchmtn = callPackage ../build-support/fetchmtn (config.fetchmtn or {}); + + fetchMavenArtifact = callPackage ../build-support/fetchmavenartifact { }; + + prefer-remote-fetch = import ../build-support/prefer-remote-fetch; + + global-platform-pro = callPackage ../development/tools/global-platform-pro/default.nix { }; + + graph-easy = callPackage ../tools/graphics/graph-easy { }; + + packer = callPackage ../development/tools/packer { }; + + packr = callPackage ../development/libraries/packr { }; + + pet = callPackage ../development/tools/pet { }; + + mod = callPackage ../development/tools/mod { }; + + broadlink-cli = callPackage ../tools/misc/broadlink-cli {}; + + mht2htm = callPackage ../tools/misc/mht2htm { }; + + fetchpatch = callPackage ../build-support/fetchpatch { }; + + fetchs3 = callPackage ../build-support/fetchs3 { }; + + fetchsvn = callPackage ../build-support/fetchsvn { }; + + fetchsvnrevision = import ../build-support/fetchsvnrevision runCommand subversion; + + fetchsvnssh = callPackage ../build-support/fetchsvnssh { }; + + fetchhg = callPackage ../build-support/fetchhg { }; + + # `fetchurl' downloads a file from the network. + fetchurl = makeOverridable (import ../build-support/fetchurl) { + inherit lib stdenvNoCC; + curl = buildPackages.curl.override (old: rec { + # break dependency cycles + fetchurl = stdenv.fetchurlBoot; + zlib = buildPackages.zlib.override { fetchurl = stdenv.fetchurlBoot; }; + pkgconfig = buildPackages.pkgconfig.override { fetchurl = stdenv.fetchurlBoot; }; + perl = buildPackages.perl.override { fetchurl = stdenv.fetchurlBoot; }; + openssl = buildPackages.openssl.override { + fetchurl = stdenv.fetchurlBoot; + inherit perl; + buildPackages = { inherit perl; }; + }; + libssh2 = buildPackages.libssh2.override { + fetchurl = stdenv.fetchurlBoot; + inherit zlib openssl; + }; + # On darwin, libkrb5 needs bootstrap_cmds which would require + # converting many packages to fetchurl_boot to avoid evaluation cycles. + # So turn gssSupport off there, and on Windows. + # On other platforms, keep the previous value. + gssSupport = + if stdenv.isDarwin || stdenv.hostPlatform.isWindows + then false + else old.gssSupport or true; # `? true` is the default + libkrb5 = buildPackages.libkrb5.override { + fetchurl = stdenv.fetchurlBoot; + inherit pkgconfig perl openssl; + keyutils = buildPackages.keyutils.override { fetchurl = stdenv.fetchurlBoot; }; + }; + nghttp2 = buildPackages.nghttp2.override { + fetchurl = stdenv.fetchurlBoot; + inherit zlib pkgconfig openssl; + c-ares = buildPackages.c-ares.override { fetchurl = stdenv.fetchurlBoot; }; + libev = buildPackages.libev.override { fetchurl = stdenv.fetchurlBoot; }; + }; + }); + }; + + fetchRepoProject = callPackage ../build-support/fetchrepoproject { }; + + fetchipfs = import ../build-support/fetchipfs { + inherit curl stdenv; + }; + + fetchzip = callPackage ../build-support/fetchzip { }; + + fetchCrate = callPackage ../build-support/rust/fetchcrate.nix { }; + + fetchFromGitHub = callPackage ../build-support/fetchgithub {}; + + fetchFromBitbucket = callPackage ../build-support/fetchbitbucket {}; + + fetchFromSavannah = callPackage ../build-support/fetchsavannah {}; + + fetchFromGitLab = callPackage ../build-support/fetchgitlab {}; + + fetchFromRepoOrCz = callPackage ../build-support/fetchrepoorcz {}; + + fetchNuGet = callPackage ../build-support/fetchnuget { }; + buildDotnetPackage = callPackage ../build-support/build-dotnet-package { }; + + fetchgx = callPackage ../build-support/fetchgx { }; + + resolveMirrorURLs = {url}: fetchurl { + showURLs = true; + inherit url; + }; + + lazydocker = callPackage ../tools/misc/lazydocker { }; + + ld-is-cc-hook = makeSetupHook { name = "ld-is-cc-hook"; } + ../build-support/setup-hooks/ld-is-cc-hook.sh; + + libredirect = callPackage ../build-support/libredirect { }; + + madonctl = callPackage ../applications/misc/madonctl { }; + + makeDesktopItem = callPackage ../build-support/make-desktopitem { }; + + makeAutostartItem = callPackage ../build-support/make-startupitem { }; + + makeInitrd = callPackage ../build-support/kernel/make-initrd.nix; # Args intentionally left out + + makeWrapper = makeSetupHook { deps = [ dieHook ]; substitutions = { shell = pkgs.runtimeShell; }; } + ../build-support/setup-hooks/make-wrapper.sh; + + makeModulesClosure = { kernel, firmware, rootModules, allowMissing ? false }: + callPackage ../build-support/kernel/modules-closure.nix { + inherit kernel firmware rootModules allowMissing; + }; + + mkShell = callPackage ../build-support/mkshell { }; + + nixBufferBuilders = import ../build-support/emacs/buffer.nix { inherit (pkgs) lib writeText; inherit (emacsPackagesNg) inherit-local; }; + + nix-gitignore = callPackage ../build-support/nix-gitignore { }; + + pathsFromGraph = ../build-support/kernel/paths-from-graph.pl; + + pruneLibtoolFiles = makeSetupHook { name = "prune-libtool-files"; } + ../build-support/setup-hooks/prune-libtool-files.sh; + + closureInfo = callPackage ../build-support/closure-info.nix { }; + + setupSystemdUnits = callPackage ../build-support/setup-systemd-units.nix { }; + + shortenPerlShebang = makeSetupHook + { deps = [ dieHook ]; } + ../build-support/setup-hooks/shorten-perl-shebang.sh; + + singularity-tools = callPackage ../build-support/singularity-tools { }; + + srcOnly = args: callPackage ../build-support/src-only args; + + substituteAll = callPackage ../build-support/substitute/substitute-all.nix { }; + + substituteAllFiles = callPackage ../build-support/substitute-files/substitute-all-files.nix { }; + + replaceDependency = callPackage ../build-support/replace-dependency.nix { }; + + nukeReferences = callPackage ../build-support/nuke-references { }; + + referencesByPopularity = callPackage ../build-support/references-by-popularity { }; + + removeReferencesTo = callPackage ../build-support/remove-references-to { }; + + vmTools = callPackage ../build-support/vm { }; + + releaseTools = callPackage ../build-support/release { }; + + inherit (lib.systems) platforms; + + setJavaClassPath = makeSetupHook { } ../build-support/setup-hooks/set-java-classpath.sh; + + fixDarwinDylibNames = makeSetupHook { } ../build-support/setup-hooks/fix-darwin-dylib-names.sh; + + keepBuildTree = makeSetupHook { } ../build-support/setup-hooks/keep-build-tree.sh; + + enableGCOVInstrumentation = makeSetupHook { } ../build-support/setup-hooks/enable-coverage-instrumentation.sh; + + makeGCOVReport = makeSetupHook + { deps = [ pkgs.lcov pkgs.enableGCOVInstrumentation ]; } + ../build-support/setup-hooks/make-coverage-analysis-report.sh; + + # intended to be used like nix-build -E 'with import {}; enableDebugging fooPackage' + enableDebugging = pkg: pkg.override { stdenv = stdenvAdapters.keepDebugInfo pkg.stdenv; }; + + findXMLCatalogs = makeSetupHook { } ../build-support/setup-hooks/find-xml-catalogs.sh; + + wrapGAppsHook = makeSetupHook { + deps = lib.optional (!stdenv.isDarwin) gnome3.dconf.lib ++ [ gtk3 librsvg makeWrapper ]; + } ../build-support/setup-hooks/wrap-gapps-hook.sh; + + separateDebugInfo = makeSetupHook { } ../build-support/setup-hooks/separate-debug-info.sh; + + setupDebugInfoDirs = makeSetupHook { } ../build-support/setup-hooks/setup-debug-info-dirs.sh; + + useOldCXXAbi = makeSetupHook { } ../build-support/setup-hooks/use-old-cxx-abi.sh; + + ical2org = callPackage ../tools/misc/ical2org {}; + + iconConvTools = callPackage ../build-support/icon-conv-tools {}; + + #package writers + writers = callPackage ../build-support/writers {}; + + ### TOOLS + + _0x0 = callPackage ../tools/misc/0x0 { }; + + _1password = callPackage ../applications/misc/1password { }; + + _9pfs = callPackage ../tools/filesystems/9pfs { }; + + a2ps = callPackage ../tools/text/a2ps { }; + + abcm2ps = callPackage ../tools/audio/abcm2ps { }; + + abcmidi = callPackage ../tools/audio/abcmidi { }; + + abduco = callPackage ../tools/misc/abduco { }; + + acct = callPackage ../tools/system/acct { }; + + accuraterip-checksum = callPackage ../tools/audio/accuraterip-checksum { }; + + acme-sh = callPackage ../tools/admin/acme.sh { }; + + acoustidFingerprinter = callPackage ../tools/audio/acoustid-fingerprinter { + ffmpeg = ffmpeg_2; + }; + + acpica-tools = callPackage ../tools/system/acpica-tools { }; + + actdiag = with python3.pkgs; toPythonApplication actdiag; + + actkbd = callPackage ../tools/system/actkbd { }; + + adafruit-ampy = callPackage ../tools/misc/adafruit-ampy { }; + + adlplug = callPackage ../applications/audio/adlplug { }; + + opnplug = callPackage ../applications/audio/adlplug { + adlplugChip = "-DADLplug_CHIP=OPN2"; + pname = "OPNplug"; + }; + + advancecomp = callPackage ../tools/compression/advancecomp {}; + + aefs = callPackage ../tools/filesystems/aefs { }; + + aegisub = callPackage ../applications/video/aegisub ({ + wxGTK = wxGTK30; + } // (config.aegisub or {})); + + aerc = callPackage ../applications/networking/mailreaders/aerc { }; + + aerospike = callPackage ../servers/nosql/aerospike { }; + + aespipe = callPackage ../tools/security/aespipe { }; + + aescrypt = callPackage ../tools/misc/aescrypt { }; + + acme-client = callPackage ../tools/networking/acme-client { inherit (darwin) apple_sdk; }; + + amass = callPackage ../tools/networking/amass { }; + + afew = callPackage ../applications/networking/mailreaders/afew { pythonPackages = python3Packages; }; + + afio = callPackage ../tools/archivers/afio { }; + + afl = callPackage ../tools/security/afl { + stdenv = clangStdenv; + }; + + libdislocator = callPackage ../tools/security/afl/libdislocator.nix { }; + + afpfs-ng = callPackage ../tools/filesystems/afpfs-ng { }; + + agrep = callPackage ../tools/text/agrep { }; + + aha = callPackage ../tools/text/aha { }; + + ahcpd = callPackage ../tools/networking/ahcpd { }; + + aide = callPackage ../tools/security/aide { }; + + aircrack-ng = callPackage ../tools/networking/aircrack-ng { }; + + airfield = callPackage ../tools/networking/airfield { }; + + airsonic = callPackage ../servers/misc/airsonic { }; + + airspy = callPackage ../applications/radio/airspy { }; + + airtame = callPackage ../applications/misc/airtame { }; + + aj-snapshot = callPackage ../applications/audio/aj-snapshot { }; + + albert = libsForQt5.callPackage ../applications/misc/albert {}; + + alacritty = callPackage ../applications/misc/alacritty { + inherit (xorg) libXcursor libXxf86vm libXi; + inherit (darwin.apple_sdk.frameworks) AppKit CoreGraphics CoreServices CoreText Foundation OpenGL; + }; + + aldo = callPackage ../applications/radio/aldo { }; + + almanah = callPackage ../applications/misc/almanah { }; + + amazon-ecs-cli = callPackage ../tools/virtualization/amazon-ecs-cli { }; + + amazon-glacier-cmd-interface = callPackage ../tools/backup/amazon-glacier-cmd-interface { }; + + amber = callPackage ../tools/text/amber { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + ammonite = callPackage ../development/tools/ammonite {}; + + amp = callPackage ../applications/editors/amp {}; + + amtterm = callPackage ../tools/system/amtterm {}; + + analog = callPackage ../tools/admin/analog {}; + + ansifilter = callPackage ../tools/text/ansifilter {}; + + antora = callPackage ../development/tools/documentation/antora {}; + + apfs-fuse = callPackage ../tools/filesystems/apfs-fuse { }; + + apktool = callPackage ../development/tools/apktool { + inherit (androidenv.androidPkgs_9_0) build-tools; + }; + + appimage-run = callPackage ../tools/package-management/appimage-run {}; + + appimagekit = callPackage ../tools/package-management/appimagekit {}; + + apt-cacher-ng = callPackage ../servers/http/apt-cacher-ng { }; + + apt-offline = callPackage ../tools/misc/apt-offline { }; + + aptly = callPackage ../tools/misc/aptly { }; + + archivemount = callPackage ../tools/filesystems/archivemount { }; + + arandr = callPackage ../tools/X11/arandr { }; + + inherit (callPackages ../servers/nosql/arangodb { }) arangodb_3_2 arangodb_3_3 arangodb_3_4 arangodb_3_5; + arangodb = arangodb_3_4; + + arcanist = callPackage ../development/tools/misc/arcanist {}; + + arduino = arduino-core.override { withGui = true; }; + + arduino-core = callPackage ../development/arduino/arduino-core { }; + + arduino-mk = callPackage ../development/arduino/arduino-mk {}; + + apitrace = libsForQt5.callPackage ../applications/graphics/apitrace {}; + + arguments = callPackage ../development/libraries/arguments { }; + + argus = callPackage ../tools/networking/argus {}; + + argus-clients = callPackage ../tools/networking/argus-clients {}; + + argtable = callPackage ../tools/misc/argtable {}; + + argyllcms = callPackage ../tools/graphics/argyllcms {}; + + arp-scan = callPackage ../tools/misc/arp-scan { }; + + inherit (callPackages ../data/fonts/arphic {}) + arphic-ukai arphic-uming; + + artyFX = callPackage ../applications/audio/artyFX {}; + + as31 = callPackage ../development/compilers/as31 {}; + + owl-lisp = callPackage ../development/compilers/owl-lisp {}; + + ascii = callPackage ../tools/text/ascii { }; + + asciinema = callPackage ../tools/misc/asciinema {}; + + asciiquarium = callPackage ../applications/misc/asciiquarium {}; + + asymptote = callPackage ../tools/graphics/asymptote { + texLive = texlive.combine { inherit (texlive) scheme-small epsf cm-super; }; + gsl = gsl_1; + }; + + atomicparsley = callPackage ../tools/video/atomicparsley { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + + autoflake = callPackage ../development/tools/analysis/autoflake { }; + + autospotting = callPackage ../applications/misc/autospotting { }; + + avfs = callPackage ../tools/filesystems/avfs { }; + + avldrums-lv2 = callPackage ../applications/audio/avldrums-lv2 { }; + + aws-iam-authenticator = callPackage ../tools/security/aws-iam-authenticator {}; + + awscli = callPackage ../tools/admin/awscli { }; + + awsebcli = callPackage ../tools/virtualization/awsebcli {}; + + awslogs = callPackage ../tools/admin/awslogs { }; + + aws-env = callPackage ../tools/admin/aws-env { }; + + aws-google-auth = python3Packages.callPackage ../tools/admin/aws-google-auth { }; + + aws-okta = callPackage ../tools/security/aws-okta { }; + + aws-rotate-key = callPackage ../tools/admin/aws-rotate-key { }; + + aws_shell = pythonPackages.callPackage ../tools/admin/aws_shell { }; + + aws-sam-cli = callPackage ../development/tools/aws-sam-cli { }; + + aws-vault = callPackage ../tools/admin/aws-vault { }; + + iamy = callPackage ../tools/admin/iamy { }; + + azure-cli = nodePackages_10_x.azure-cli; + + azure-storage-azcopy = callPackage ../development/tools/azcopy { }; + + azure-vhd-utils = callPackage ../tools/misc/azure-vhd-utils { }; + + awless = callPackage ../tools/virtualization/awless { }; + + brakeman = callPackage ../development/tools/analysis/brakeman { }; + + brewtarget = libsForQt5.callPackage ../applications/misc/brewtarget { } ; + + ec2_api_tools = callPackage ../tools/virtualization/ec2-api-tools { }; + + ec2_ami_tools = callPackage ../tools/virtualization/ec2-ami-tools { }; + + altermime = callPackage ../tools/networking/altermime {}; + + alttab = callPackage ../tools/X11/alttab { }; + + amule = callPackage ../tools/networking/p2p/amule { }; + + amuleDaemon = appendToName "daemon" (amule.override { + monolithic = false; + daemon = true; + }); + + amuleGui = appendToName "gui" (amule.override { + monolithic = false; + client = true; + }); + + apg = callPackage ../tools/security/apg { }; + + apt = callPackage ../tools/package-management/apt { + # include/c++/6.4.0/cstdlib:75:25: fatal error: stdlib.h: No such file or directory + stdenv = gcc5Stdenv; + }; + + apt-dater = callPackage ../tools/package-management/apt-dater { }; + + autorevision = callPackage ../tools/misc/autorevision { }; + + automirror = callPackage ../tools/misc/automirror { }; + + bcachefs-tools = callPackage ../tools/filesystems/bcachefs-tools { }; + + bitwarden = callPackage ../tools/security/bitwarden { }; + + bitwarden-cli = callPackage ../tools/security/bitwarden-cli { }; + + bitwarden_rs = callPackage ../tools/security/bitwarden_rs { + inherit (darwin.apple_sdk.frameworks) Security CoreServices; + }; + + bitwarden_rs-vault = callPackage ../tools/security/bitwarden_rs/vault.nix { }; + + bmap-tools = callPackage ../tools/misc/bmap-tools { }; + + bonnie = callPackage ../tools/filesystems/bonnie { }; + + bonfire = callPackage ../tools/misc/bonfire { }; + + buildbot = with python3Packages; toPythonApplication buildbot; + buildbot-ui = with python3Packages; toPythonApplication buildbot-ui; + buildbot-full = with python3Packages; toPythonApplication buildbot-full; + buildbot-worker = with python3Packages; toPythonApplication buildbot-worker; + + bunny = callPackage ../tools/package-management/bunny { }; + + certigo = callPackage ../tools/admin/certigo { }; + + chezmoi = callPackage ../tools/misc/chezmoi { }; + + chipsec = callPackage ../tools/security/chipsec { + kernel = null; + withDriver = false; + }; + + clair = callPackage ../tools/admin/clair { }; + + cloud-sql-proxy = callPackage ../tools/misc/cloud-sql-proxy { }; + + container-linux-config-transpiler = callPackage ../development/tools/container-linux-config-transpiler { }; + + ccextractor = callPackage ../applications/video/ccextractor { }; + + cconv = callPackage ../tools/text/cconv { }; + + go-check = callPackage ../development/tools/check { }; + + chkcrontab = callPackage ../tools/admin/chkcrontab { }; + + codespell = with python3Packages; toPythonApplication codespell; + + cozy = callPackage ../applications/audio/cozy-audiobooks { }; + + ctrtool = callPackage ../tools/archivers/ctrtool { }; + + crumbs = callPackage ../applications/misc/crumbs { }; + + crc32c = callPackage ../development/libraries/crc32c { }; + + cue = callPackage ../development/tools/cue { }; + + deskew = callPackage ../applications/graphics/deskew { }; + + detect-secrets = python3Packages.callPackage ../development/tools/detect-secrets { }; + + diskus = callPackage ../tools/misc/diskus { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + djmount = callPackage ../tools/filesystems/djmount { }; + + dgsh = callPackage ../shells/dgsh { }; + + dkimpy = with pythonPackages; toPythonApplication dkimpy; + + dpt-rp1-py = callPackage ../tools/misc/dpt-rp1-py { }; + + ecdsautils = callPackage ../tools/security/ecdsautils { }; + + sedutil = callPackage ../tools/security/sedutil { }; + + elvish = callPackage ../shells/elvish { }; + + encryptr = callPackage ../tools/security/encryptr { + gconf = gnome2.GConf; + }; + + enchive = callPackage ../tools/security/enchive { }; + + enpass = callPackage ../tools/security/enpass { }; + + esh = callPackage ../tools/text/esh { }; + + ezstream = callPackage ../tools/audio/ezstream { }; + + fxlinuxprintutil = callPackage ../tools/misc/fxlinuxprintutil { }; + + genymotion = callPackage ../development/mobile/genymotion { }; + + gamecube-tools = callPackage ../development/tools/gamecube-tools { }; + + gams = callPackage ../tools/misc/gams (config.gams or {}); + + git-fire = callPackage ../tools/misc/git-fire { }; + + git-repo-updater = python3Packages.callPackage ../development/tools/git-repo-updater { }; + + git-revise = with python3Packages; toPythonApplication git-revise; + + git-town = callPackage ../tools/misc/git-town { }; + + github-changelog-generator = callPackage ../development/tools/github-changelog-generator { }; + + github-commenter = callPackage ../development/tools/github-commenter { }; + + gitless = callPackage ../applications/version-management/gitless { }; + + gitter = callPackage ../applications/networking/instant-messengers/gitter { }; + + gucci = callPackage ../tools/text/gucci { }; + + grc = callPackage ../tools/misc/grc { }; + + green-pdfviewer = callPackage ../applications/misc/green-pdfviewer { + SDL = SDL_sixel; + }; + + gremlin-console = callPackage ../applications/misc/gremlin-console { }; + + gcsfuse = callPackage ../tools/filesystems/gcsfuse { }; + + glyr = callPackage ../tools/audio/glyr { }; + + httperf = callPackage ../tools/networking/httperf { }; + + ili2c = callPackage ../tools/misc/ili2c { }; + + imgpatchtools = callPackage ../development/mobile/imgpatchtools { }; + + ipgrep = callPackage ../tools/networking/ipgrep { }; + + lastpass-cli = callPackage ../tools/security/lastpass-cli { }; + + lesspass-cli = callPackage ../tools/security/lesspass-cli { }; + + pacparser = callPackage ../tools/networking/pacparser { }; + + pass = callPackage ../tools/security/pass { }; + + passExtensions = recurseIntoAttrs pass.extensions; + + asc-key-to-qr-code-gif = callPackage ../tools/security/asc-key-to-qr-code-gif { }; + + gopass = callPackage ../tools/security/gopass { }; + + browserpass = callPackage ../tools/security/browserpass { }; + + passff-host = callPackage ../tools/security/passff-host { }; + + oracle-instantclient = callPackage ../development/libraries/oracle-instantclient { }; + + goku = callPackage ../os-specific/darwin/goku { }; + + kwakd = callPackage ../servers/kwakd { }; + + chunkwm = callPackage ../os-specific/darwin/chunkwm { + inherit (darwin.apple_sdk.frameworks) Carbon Cocoa ScriptingBridge; + }; + + kwm = callPackage ../os-specific/darwin/kwm { }; + + khd = callPackage ../os-specific/darwin/khd { + inherit (darwin.apple_sdk.frameworks) Carbon Cocoa; + }; + + kjv = callPackage ../applications/misc/kjv { }; + + luigi = callPackage ../applications/networking/cluster/luigi { }; + + m-cli = callPackage ../os-specific/darwin/m-cli { }; + + reattach-to-user-namespace = callPackage ../os-specific/darwin/reattach-to-user-namespace {}; + + skhd = callPackage ../os-specific/darwin/skhd { + inherit (darwin.apple_sdk.frameworks) Carbon; + }; + + qes = callPackage ../os-specific/darwin/qes { + inherit (darwin.apple_sdk.frameworks) Carbon; + }; + + wiiload = callPackage ../development/tools/wiiload { }; + + xcodeenv = callPackage ../development/mobile/xcodeenv { }; + + ssh-agents = callPackage ../tools/networking/ssh-agents { }; + + titaniumenv = callPackage ../development/mobile/titaniumenv { }; + + abootimg = callPackage ../development/mobile/abootimg {}; + + adbfs-rootless = callPackage ../development/mobile/adbfs-rootless { + adb = androidenv.androidPkgs_9_0.platform-tools; + }; + + adb-sync = callPackage ../development/mobile/adb-sync { + inherit (androidenv.androidPkgs_9_0) platform-tools; + }; + + anbox = callPackage ../os-specific/linux/anbox { }; + + androidenv = callPackage ../development/mobile/androidenv { + pkgs_i686 = pkgsi686Linux; + }; + + androidndkPkgs = androidndkPkgs_18b; + androidndkPkgs_18b = (callPackage ../development/androidndk-pkgs {})."18b"; + + androidsdk_9_0 = androidenv.androidPkgs_9_0.androidsdk; + + webos = recurseIntoAttrs { + cmake-modules = callPackage ../development/mobile/webos/cmake-modules.nix { }; + + novacom = callPackage ../development/mobile/webos/novacom.nix { }; + novacomd = callPackage ../development/mobile/webos/novacomd.nix { }; + }; + + arc-theme = callPackage ../misc/themes/arc { }; + + arc-kde-theme = callPackage ../misc/themes/arc-kde { }; + + adapta-gtk-theme = callPackage ../misc/themes/adapta { }; + + adapta-kde-theme = callPackage ../misc/themes/adapta-kde { }; + + aria2 = callPackage ../tools/networking/aria2 { + inherit (darwin.apple_sdk.frameworks) Security; + inherit (pythonPackages) sphinx; + }; + aria = aria2; + + asmfmt = callPackage ../development/tools/asmfmt { }; + + aspcud = callPackage ../tools/misc/aspcud { }; + + at = callPackage ../tools/system/at { }; + + atftp = callPackage ../tools/networking/atftp { }; + + autogen = callPackage ../development/tools/misc/autogen { + guile = guile_2_0; + }; + + autojump = callPackage ../tools/misc/autojump { }; + + automysqlbackup = callPackage ../tools/backup/automysqlbackup { }; + + autorandr = callPackage ../tools/misc/autorandr {}; + + avahi = callPackage ../development/libraries/avahi (config.avahi or {}); + + avahi-compat = callPackage ../development/libraries/avahi ((config.avahi or {}) // { + withLibdnssdCompat = true; + }); + + avro-c = callPackage ../development/libraries/avro-c { }; + + avro-cpp = callPackage ../development/libraries/avro-c++ { boost = boost160; }; + + aws = callPackage ../tools/virtualization/aws { }; + + aws_mturk_clt = callPackage ../tools/misc/aws-mturk-clt { }; + + awstats = callPackage ../tools/system/awstats { }; + + axel = callPackage ../tools/networking/axel { + libssl = openssl; + }; + + axoloti = callPackage ../applications/audio/axoloti { + gcc-arm-embedded = pkgsCross.arm-embedded.buildPackages.gcc; + binutils-arm-embedded = pkgsCross.arm-embedded.buildPackages.binutils; + }; + dfu-util-axoloti = callPackage ../applications/audio/axoloti/dfu-util.nix { }; + libusb1-axoloti = callPackage ../applications/audio/axoloti/libusb1.nix { + inherit (darwin) libobjc; + inherit (darwin.apple_sdk.frameworks) IOKit; + }; + + azureus = callPackage ../tools/networking/p2p/azureus { }; + + backblaze-b2 = python.pkgs.callPackage ../development/tools/backblaze-b2 { }; + + bar = callPackage ../tools/system/bar {}; + + base16-shell-preview = callPackage ../misc/base16-shell-preview { }; + + base16-builder = callPackage ../misc/base16-builder { }; + + basex = callPackage ../tools/text/xml/basex { }; + + bashplotlib = callPackage ../tools/misc/bashplotlib { }; + + babeld = callPackage ../tools/networking/babeld { }; + + badvpn = callPackage ../tools/networking/badvpn {}; + + barcode = callPackage ../tools/graphics/barcode {}; + + bashburn = callPackage ../tools/cd-dvd/bashburn { }; + + bashmount = callPackage ../tools/filesystems/bashmount {}; + + bat = callPackage ../tools/misc/bat { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + bc = callPackage ../tools/misc/bc { }; + + bdf2psf = callPackage ../tools/misc/bdf2psf { }; + + bcat = callPackage ../tools/text/bcat {}; + + bcache-tools = callPackage ../tools/filesystems/bcache-tools { }; + + bchunk = callPackage ../tools/cd-dvd/bchunk { }; + + inherit (callPackages ../misc/logging/beats/5.x.nix { + # XXX: this is failing with Go 1.12. Error is related to cgo, an + # update to this package might fix it. + buildGoPackage = buildGo111Package; + }) + filebeat5 + heartbeat5 + metricbeat5 + packetbeat5; + + journalbeat5 = callPackage ../tools/system/journalbeat { }; + + inherit (callPackages ../misc/logging/beats/6.x.nix { + # XXX: this is failing with Go 1.12. Error is related to cgo, an + # update to this package might fix it. + buildGoPackage = buildGo111Package; + }) + filebeat6 + heartbeat6 + metricbeat6 + packetbeat6 + journalbeat6; + + inherit (callPackages ../misc/logging/beats/7.x.nix { + # XXX: this is failing with Go 1.12. Error is related to cgo, an + # update to this package might fix it. + buildGoPackage = buildGo111Package; + }) + filebeat7 + heartbeat7 + metricbeat7 + packetbeat7 + journalbeat7; + + filebeat = filebeat6; + heartbeat = heartbeat6; + metricbeat = metricbeat6; + packetbeat = packetbeat6; + journalbeat = journalbeat6; + + bfr = callPackage ../tools/misc/bfr { }; + + bibtool = callPackage ../tools/misc/bibtool { }; + + bibutils = callPackage ../tools/misc/bibutils { }; + + bibtex2html = callPackage ../tools/misc/bibtex2html { }; + + bicon = callPackage ../applications/misc/bicon { }; + + bindfs = callPackage ../tools/filesystems/bindfs { }; + + bitbucket-cli = python2Packages.bitbucket-cli; + + blink = callPackage ../applications/networking/instant-messengers/blink { }; + + blockbook = callPackage ../servers/blockbook { }; + + blockhash = callPackage ../tools/graphics/blockhash { }; + + bluemix-cli = callPackage ../tools/admin/bluemix-cli { }; + + blur-effect = callPackage ../tools/graphics/blur-effect { }; + + charles = charles4; + inherit (callPackage ../applications/networking/charles {}) + charles3 + charles4 + ; + + inherit (libsForQt5.callPackage ../development/libraries/libqmatrixclient { }) + libqmatrixclient_0_4 + libqmatrixclient_0_5 + libqmatrixclient; + + inherit (libsForQt5.callPackage ../applications/networking/instant-messengers/quaternion { }) + quaternion + quaternion-git; + + tensor = libsForQt5.callPackage ../applications/networking/instant-messengers/tensor { }; + + libtensorflow-bin = callPackage ../development/libraries/science/math/tensorflow/bin.nix { + cudaSupport = pkgs.config.cudaSupport or false; + inherit (linuxPackages) nvidia_x11; + cudatoolkit = cudatoolkit_10_0; + cudnn = cudnn_cudatoolkit_10_0; + }; + + libtensorflow = + if python.pkgs.tensorflow ? libtensorflow + then python.pkgs.tensorflow.libtensorflow + else libtensorflow-bin; + + behdad-fonts = callPackage ../data/fonts/behdad-fonts { }; + + blink1-tool = callPackage ../tools/misc/blink1-tool { }; + + bliss = callPackage ../applications/science/math/bliss { }; + + blitz = callPackage ../development/libraries/blitz { + boost = boost160; + }; + + blobfuse = callPackage ../tools/filesystems/blobfuse { }; + + blockdiag = with python3Packages; toPythonApplication blockdiag; + + blsd = callPackage ../tools/misc/blsd { }; + + bluez-alsa = callPackage ../tools/bluetooth/bluez-alsa { }; + + bluez-tools = callPackage ../tools/bluetooth/bluez-tools { }; + + bmon = callPackage ../tools/misc/bmon { }; + + bmake = callPackage ../development/tools/build-managers/bmake { }; + + bochs = callPackage ../applications/virtualization/bochs { }; + + bubblewrap = callPackage ../tools/admin/bubblewrap { }; + + borgbackup = callPackage ../tools/backup/borg { }; + + boringtun = callPackage ../tools/networking/boringtun { }; + + boomerang = libsForQt5.callPackage ../development/tools/boomerang { }; + + boost-build = callPackage ../development/tools/boost-build { }; + + boot = callPackage ../development/tools/build-managers/boot { }; + + bootchart = callPackage ../tools/system/bootchart { }; + + bowtie2 = callPackage ../applications/science/biology/bowtie2 { }; + + boxfs = callPackage ../tools/filesystems/boxfs { }; + + brasero-original = lowPrio (callPackage ../tools/cd-dvd/brasero { }); + + brasero = callPackage ../tools/cd-dvd/brasero/wrapper.nix { }; + + brigand = callPackage ../development/libraries/brigand { }; + + brltty = callPackage ../tools/misc/brltty { }; + + bro = callPackage ../applications/networking/ids/bro { + openssl = openssl_1_0_2; + }; + + brook = callPackage ../tools/networking/brook { }; + + broot = callPackage ../tools/misc/broot { }; + + bruteforce-luks = callPackage ../tools/security/bruteforce-luks { }; + + breakpointHook = assert stdenv.isLinux; + makeSetupHook { } ../build-support/setup-hooks/breakpoint-hook.sh; + + bsod = callPackage ../misc/emulators/bsod { }; + + btrfs-progs = callPackage ../tools/filesystems/btrfs-progs { }; + + btrfs-dedupe = callPackage ../tools/filesystems/btrfs-dedupe {}; + + btrbk = callPackage ../tools/backup/btrbk { + asciidoc = asciidoc-full; + }; + + buildtorrent = callPackage ../tools/misc/buildtorrent { }; + + bustle = haskellPackages.bustle; + + buttersink = callPackage ../tools/filesystems/buttersink { }; + + bwm_ng = callPackage ../tools/networking/bwm-ng { }; + + byobu = callPackage ../tools/misc/byobu { + # Choices: [ tmux screen ]; + textual-window-manager = tmux; + }; + + bsh = fetchurl { + url = http://www.beanshell.org/bsh-2.0b5.jar; + sha256 = "0p2sxrpzd0vsk11zf3kb5h12yl1nq4yypb5mpjrm8ww0cfaijck2"; + }; + + btfs = callPackage ../os-specific/linux/btfs { }; + + buildah = callPackage ../development/tools/buildah { }; + + buildkit = callPackage ../development/tools/buildkit { }; + + bukubrow = callPackage ../tools/networking/bukubrow { }; + + burpsuite = callPackage ../tools/networking/burpsuite {}; + + c3d = callPackage ../applications/graphics/c3d { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + + cue2pops = callPackage ../tools/cd-dvd/cue2pops { }; + + cabal2nix = haskell.lib.overrideCabal (haskell.lib.generateOptparseApplicativeCompletion "cabal2nix" haskellPackages.cabal2nix) (drv: { + isLibrary = false; + enableSharedExecutables = false; + executableToolDepends = (drv.executableToolDepends or []) ++ [ makeWrapper ]; + postInstall = '' + exe=$out/libexec/${drv.pname}-${drv.version}/${drv.pname} + install -D $out/bin/${drv.pname} $exe + rm -rf $out/{bin,lib,share} + makeWrapper $exe $out/bin/${drv.pname} \ + --prefix PATH ":" "${nix}/bin" \ + --prefix PATH ":" "${nix-prefetch-scripts}/bin" + '' + (drv.postInstall or ""); + }); + + stack2nix = with haskell.lib; overrideCabal (justStaticExecutables haskellPackages.stack2nix) (drv: { + executableToolDepends = [ makeWrapper ]; + postInstall = '' + wrapProgram $out/bin/stack2nix \ + --prefix PATH ":" "${git}/bin:${cabal-install}/bin" + ''; + }); + + caddy = callPackage ../servers/caddy { }; + traefik = callPackage ../servers/traefik { }; + + calamares = libsForQt5.callPackage ../tools/misc/calamares { + python = python3; + boost = pkgs.boost.override { python = python3; }; + }; + + candle = libsForQt5.callPackage ../applications/misc/candle { }; + + capstone = callPackage ../development/libraries/capstone { }; + unicorn-emu = callPackage ../development/libraries/unicorn-emu { }; + + casync = callPackage ../applications/networking/sync/casync { + sphinx = python3Packages.sphinx; + }; + + cataract = callPackage ../applications/misc/cataract { }; + cataract-unstable = callPackage ../applications/misc/cataract/unstable.nix { }; + + catch = callPackage ../development/libraries/catch { }; + + catch2 = callPackage ../development/libraries/catch2 { }; + + catdoc = callPackage ../tools/text/catdoc { }; + + catdocx = callPackage ../tools/text/catdocx { }; + + catclock = callPackage ../applications/misc/catclock { }; + + cardpeek = callPackage ../applications/misc/cardpeek { }; + + cde = callPackage ../tools/package-management/cde { }; + + cdemu-daemon = callPackage ../misc/emulators/cdemu/daemon.nix { }; + + cdemu-client = callPackage ../misc/emulators/cdemu/client.nix { }; + + ceres-solver = callPackage ../development/libraries/ceres-solver { + gflags = null; # only required for examples/tests + }; + + gcdemu = callPackage ../misc/emulators/cdemu/gui.nix { }; + + image-analyzer = callPackage ../misc/emulators/cdemu/analyzer.nix { }; + + cbor-diag = callPackage ../development/tools/cbor-diag { }; + + ccnet = callPackage ../tools/networking/ccnet { }; + + croc = callPackage ../tools/networking/croc { }; + + cddl = callPackage ../development/tools/cddl { }; + + cedille = callPackage ../applications/science/logic/cedille + { inherit (haskellPackages) alex happy Agda ghcWithPackages; + }; + + cfdyndns = callPackage ../applications/networking/dyndns/cfdyndns { }; + + charliecloud = callPackage ../applications/virtualization/charliecloud { }; + + chelf = callPackage ../tools/misc/chelf { }; + + cht-sh = callPackage ../tools/misc/cht.sh { }; + + ckbcomp = callPackage ../tools/X11/ckbcomp { }; + + clac = callPackage ../tools/misc/clac {}; + + clasp = callPackage ../tools/misc/clasp { }; + + cli53 = callPackage ../tools/admin/cli53 { }; + + cli-visualizer = callPackage ../applications/misc/cli-visualizer { }; + + clog-cli = callPackage ../development/tools/clog-cli { }; + + cloud-init = callPackage ../tools/virtualization/cloud-init { }; + + cloudflared = callPackage ../applications/networking/cloudflared { }; + + cloudmonkey = callPackage ../tools/virtualization/cloudmonkey { }; + + clib = callPackage ../tools/package-management/clib { }; + + clingo = callPackage ../applications/science/logic/potassco/clingo.nix { }; + + clprover = callPackage ../applications/science/logic/clprover/clprover.nix { }; + + coloredlogs = with python3Packages; toPythonApplication coloredlogs; + + colord-kde = libsForQt5.callPackage ../tools/misc/colord-kde {}; + + colpack = callPackage ../applications/science/math/colpack { }; + + compactor = callPackage ../applications/networking/compactor { }; + + consul = callPackage ../servers/consul { }; + + consul-alerts = callPackage ../servers/monitoring/consul-alerts { }; + + consul-template = callPackage ../tools/system/consul-template { }; + + copyright-update = callPackage ../tools/text/copyright-update { }; + + corebird = callPackage ../applications/networking/corebird { }; + + corosync = callPackage ../servers/corosync { }; + + cowsay = callPackage ../tools/misc/cowsay { }; + + cherrytree = callPackage ../applications/misc/cherrytree { }; + + chntpw = callPackage ../tools/security/chntpw { }; + + clipster = callPackage ../tools/misc/clipster { }; + + coprthr = callPackage ../development/libraries/coprthr { }; + + cplex = callPackage ../applications/science/math/cplex (config.cplex or {}); + + cpulimit = callPackage ../tools/misc/cpulimit { }; + + codesearch = callPackage ../tools/text/codesearch { }; + + codec2 = callPackage ../development/libraries/codec2 { }; + + contacts = callPackage ../tools/misc/contacts { + inherit (darwin.apple_sdk.frameworks) Foundation AddressBook; + xcbuildHook = xcbuild6Hook; + }; + + colorls = callPackage ../tools/system/colorls { }; + + coloursum = callPackage ../tools/text/coloursum { }; + + compsize = callPackage ../os-specific/linux/compsize { }; + + coturn = callPackage ../servers/coturn { }; + + coursier = callPackage ../development/tools/coursier {}; + + cppclean = callPackage ../development/tools/cppclean {}; + + crex = callPackage ../tools/misc/crex { }; + + cri-tools = callPackage ../tools/virtualization/cri-tools {}; + + crip = callPackage ../applications/audio/crip { }; + + crunch = callPackage ../tools/security/crunch { }; + + crudini = callPackage ../tools/misc/crudini { }; + + csvkit = callPackage ../tools/text/csvkit { }; + + csvs-to-sqlite = with python3Packages; toPythonApplication csvs-to-sqlite; + + cucumber = callPackage ../development/tools/cucumber {}; + + dabtools = callPackage ../applications/radio/dabtools { }; + + daemontools = callPackage ../tools/admin/daemontools { }; + + dale = callPackage ../development/compilers/dale { }; + + dante = callPackage ../servers/dante { }; + + datamash = callPackage ../tools/misc/datamash { }; + + datasette = with python3Packages; toPythonApplication datasette; + + datefudge = callPackage ../tools/system/datefudge { }; + + dateutils = callPackage ../tools/misc/dateutils { }; + + ddar = callPackage ../tools/backup/ddar { }; + + ddate = callPackage ../tools/misc/ddate { }; + + dedup = callPackage ../tools/backup/dedup { }; + + dehydrated = callPackage ../tools/admin/dehydrated { }; + + deis = callPackage ../development/tools/deis {}; + + deisctl = callPackage ../development/tools/deisctl {}; + + deja-dup = callPackage ../applications/backup/deja-dup { }; + + dejsonlz4 = callPackage ../tools/compression/dejsonlz4 { }; + + desync = callPackage ../applications/networking/sync/desync { }; + + devmem2 = callPackage ../os-specific/linux/devmem2 { }; + + dbus-broker = callPackage ../os-specific/linux/dbus-broker { }; + + ioport = callPackage ../os-specific/linux/ioport {}; + + diagrams-builder = callPackage ../tools/graphics/diagrams-builder { + inherit (haskellPackages) ghcWithPackages diagrams-builder; + }; + + dialog = callPackage ../development/tools/misc/dialog { }; + + dibbler = callPackage ../tools/networking/dibbler { }; + + ding = callPackage ../applications/misc/ding { + aspellDicts_de = aspellDicts.de; + aspellDicts_en = aspellDicts.en; + }; + + dirb = callPackage ../tools/networking/dirb { }; + + direnv = callPackage ../tools/misc/direnv { }; + + discount = callPackage ../tools/text/discount { }; + + diskscan = callPackage ../tools/misc/diskscan { }; + + disorderfs = callPackage ../tools/filesystems/disorderfs { + asciidoc = asciidoc-full; + }; + + dislocker = callPackage ../tools/filesystems/dislocker { }; + + distgen = callPackage ../development/tools/distgen {}; + + distrobuilder = callPackage ../tools/virtualization/distrobuilder { }; + + ditaa = callPackage ../tools/graphics/ditaa { }; + + dino = callPackage ../applications/networking/instant-messengers/dino { }; + + dlx = callPackage ../misc/emulators/dlx { }; + + doitlive = callPackage ../tools/misc/doitlive { }; + + dosage = callPackage ../applications/graphics/dosage { + pythonPackages = python3Packages; + }; + + dozenal = callPackage ../applications/misc/dozenal { }; + + dpic = callPackage ../tools/graphics/dpic { }; + + dragon-drop = callPackage ../tools/X11/dragon-drop { + gtk = gtk3; + }; + + dsvpn = callPackage ../applications/networking/dsvpn { }; + + dtools = callPackage ../development/tools/dtools { }; + + dtrx = callPackage ../tools/compression/dtrx { }; + + dua = callPackage ../tools/misc/dua { }; + + inherit (ocamlPackages) dune; + + duperemove = callPackage ../tools/filesystems/duperemove { }; + + dylibbundler = callPackage ../tools/misc/dylibbundler { }; + + dynamic-colors = callPackage ../tools/misc/dynamic-colors { }; + + dyncall = callPackage ../development/libraries/dyncall { }; + + earlyoom = callPackage ../os-specific/linux/earlyoom { }; + + EBTKS = callPackage ../development/libraries/science/biology/EBTKS { }; + + ecasound = callPackage ../applications/audio/ecasound { }; + + edac-utils = callPackage ../os-specific/linux/edac-utils { }; + + eggdrop = callPackage ../tools/networking/eggdrop { }; + + eksctl = callPackage ../tools/admin/eksctl { }; + + elementary-xfce-icon-theme = callPackage ../data/icons/elementary-xfce-icon-theme { }; + + ell = callPackage ../os-specific/linux/ell { }; + + elm-github-install = callPackage ../tools/package-management/elm-github-install { }; + + enca = callPackage ../tools/text/enca { }; + + ent = callPackage ../tools/misc/ent { }; + + envconsul = callPackage ../tools/system/envconsul { }; + + envsubst = callPackage ../tools/misc/envsubst { }; + + errcheck = callPackage ../development/tools/errcheck { }; + + eschalot = callPackage ../tools/security/eschalot { }; + + esphome = callPackage ../servers/home-assistant/esphome.nix { }; + + esptool = callPackage ../tools/misc/esptool { }; + + esptool-ck = callPackage ../tools/misc/esptool-ck { }; + + ephemeralpg = callPackage ../development/tools/database/ephemeralpg {}; + + et = callPackage ../applications/misc/et {}; + + ejson = callPackage ../development/tools/ejson {}; + + eternal-terminal = callPackage ../tools/networking/eternal-terminal {}; + + f3 = callPackage ../tools/filesystems/f3 { }; + + fac = callPackage ../development/tools/fac { }; + + facedetect = callPackage ../tools/graphics/facedetect { }; + + facter = callPackage ../tools/system/facter { }; + + fasd = callPackage ../tools/misc/fasd { }; + + fastJson = callPackage ../development/libraries/fastjson { }; + + fast-cli = nodePackages.fast-cli; + + fd = callPackage ../tools/misc/fd { }; + + fdroidserver = python3Packages.callPackage ../development/tools/fdroidserver { }; + + filebench = callPackage ../tools/misc/filebench { + bison = bison2; + }; + + fileshelter = callPackage ../servers/web-apps/fileshelter { }; + + firecracker = callPackage ../applications/virtualization/firecracker { }; + + firestarter = callPackage ../applications/misc/firestarter { }; + + fsmon = callPackage ../tools/misc/fsmon { }; + + fsql = callPackage ../tools/misc/fsql { }; + + fop = callPackage ../tools/typesetting/fop { }; + + fondu = callPackage ../tools/misc/fondu { }; + + fpp = callPackage ../tools/misc/fpp { }; + + fsmark = callPackage ../tools/misc/fsmark { }; + + futhark = haskell.lib.justStaticExecutables haskellPackages.futhark; + + fwup = callPackage ../tools/misc/fwup { }; + + fzf = callPackage ../tools/misc/fzf { }; + + fzy = callPackage ../tools/misc/fzy { }; + + g2o = callPackage ../development/libraries/g2o { }; + + gbsplay = callPackage ../applications/audio/gbsplay { }; + + gdrivefs = python27Packages.gdrivefs; + + gdrive = callPackage ../applications/networking/gdrive { }; + + go-2fa = callPackage ../tools/security/2fa {}; + + go-dependency-manager = callPackage ../development/tools/gdm { }; + + geckodriver = callPackage ../development/tools/geckodriver { }; + + geekbench = callPackage ../tools/misc/geekbench { }; + + gencfsm = callPackage ../tools/security/gencfsm { }; + + genromfs = callPackage ../tools/filesystems/genromfs { }; + + gh-ost = callPackage ../tools/misc/gh-ost { }; + + ghidra-bin = callPackage ../tools/security/ghidra { }; + + gif-for-cli = callPackage ../tools/misc/gif-for-cli { }; + + gist = callPackage ../tools/text/gist { }; + + gixy = callPackage ../tools/admin/gixy { }; + + gllvm = callPackage ../development/tools/gllvm { }; + + glide = callPackage ../development/tools/glide { }; + + globalarrays = callPackage ../development/libraries/globalarrays { }; + + glock = callPackage ../development/tools/glock { }; + + glslviewer = callPackage ../development/tools/glslviewer { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + + gmic = callPackage ../tools/graphics/gmic { }; + + gmic_krita_qt = libsForQt5.callPackage ../tools/graphics/gmic_krita_qt { }; + + goa = callPackage ../development/tools/goa { + buildGoPackage = buildGo110Package; + }; + + gohai = callPackage ../tools/system/gohai { }; + + gorilla-bin = callPackage ../tools/security/gorilla-bin { }; + + gosu = callPackage ../tools/misc/gosu { }; + + gping = callPackage ../tools/networking/gping { }; + + greg = callPackage ../applications/audio/greg { + pythonPackages = python3Packages; + }; + + grim = callPackage ../tools/graphics/grim { }; + + gringo = callPackage ../tools/misc/gringo { }; + + grobi = callPackage ../tools/X11/grobi { }; + + gscan2pdf = callPackage ../applications/graphics/gscan2pdf { }; + + gsctl = callPackage ../applications/misc/gsctl { }; + + gthree = callPackage ../development/libraries/gthree { }; + + gti = callPackage ../tools/misc/gti { }; + + hdate = callPackage ../applications/misc/hdate { }; + + heatseeker = callPackage ../tools/misc/heatseeker { }; + + hebcal = callPackage ../tools/misc/hebcal {}; + + hexio = callPackage ../development/tools/hexio { }; + + hexyl = callPackage ../tools/misc/hexyl { }; + + hid-listen = callPackage ../tools/misc/hid-listen { }; + + hocr-tools = with python3Packages; toPythonApplication hocr-tools; + + home-manager = callPackage ../tools/package-management/home-manager {}; + + hostsblock = callPackage ../tools/misc/hostsblock { }; + + hopper = callPackage ../development/tools/analysis/hopper {}; + + hr = callPackage ../applications/misc/hr { }; + + hyx = callPackage ../tools/text/hyx { }; + + icdiff = callPackage ../tools/text/icdiff {}; + + interlock = callPackage ../servers/interlock {}; + + jellyfin = callPackage ../servers/jellyfin { }; + + kapacitor = callPackage ../servers/monitoring/kapacitor { }; + + kisslicer = callPackage ../tools/misc/kisslicer { }; + + klaus = with pythonPackages; toPythonApplication klaus; + + lcdproc = callPackage ../servers/monitoring/lcdproc { }; + + languagetool = callPackage ../tools/text/languagetool { }; + + lepton = callPackage ../tools/graphics/lepton { }; + + lief = callPackage ../development/libraries/lief {}; + + libndtypes = callPackage ../development/libraries/libndtypes { }; + + libxnd = callPackage ../development/libraries/libxnd { }; + + link-grammar = callPackage ../tools/text/link-grammar { }; + + linuxptp = callPackage ../os-specific/linux/linuxptp { }; + + loadwatch = callPackage ../tools/system/loadwatch { }; + + loccount = callPackage ../development/tools/misc/loccount { }; + + long-shebang = callPackage ../misc/long-shebang {}; + + numatop = callPackage ../os-specific/linux/numatop { }; + + iio-sensor-proxy = callPackage ../os-specific/linux/iio-sensor-proxy { }; + + ipvsadm = callPackage ../os-specific/linux/ipvsadm { }; + + ir-standard-fonts = callPackage ../data/fonts/ir-standard-fonts { }; + + lynis = callPackage ../tools/security/lynis { }; + + marlin-calc = callPackage ../tools/misc/marlin-calc {}; + + mathics = pythonPackages.mathics; + + masscan = callPackage ../tools/security/masscan { + stdenv = gccStdenv; + }; + + massren = callPackage ../tools/misc/massren { }; + + megasync = libsForQt5.callPackage ../applications/misc/megasync { }; + + meritous = callPackage ../games/meritous { }; + + opendune = callPackage ../games/opendune { }; + + meson = callPackage ../development/tools/build-managers/meson { }; + + metabase = callPackage ../servers/metabase { }; + + mididings = callPackage ../tools/audio/mididings { }; + + miniserve = callPackage ../tools/misc/miniserve { }; + + mkspiffs = callPackage ../tools/filesystems/mkspiffs { }; + + mkspiffs-presets = recurseIntoAttrs (callPackages ../tools/filesystems/mkspiffs/presets.nix { }); + + mlarchive2maildir = callPackage ../applications/networking/mailreaders/mlarchive2maildir { }; + + monetdb = callPackage ../servers/sql/monetdb { }; + + mousetweaks = callPackage ../applications/accessibility/mousetweaks { + inherit (pkgs.xorg) libX11 libXtst libXfixes; + }; + + mp3blaster = callPackage ../applications/audio/mp3blaster { }; + + mp3cat = callPackage ../tools/audio/mp3cat {}; + + mp3fs = callPackage ../tools/filesystems/mp3fs { }; + + mpdas = callPackage ../tools/audio/mpdas { }; + + mpdcron = callPackage ../tools/audio/mpdcron { }; + + mpdris2 = callPackage ../tools/audio/mpdris2 { }; + + mpd-mpris = callPackage ../tools/audio/mpd-mpris { }; + + mq-cli = callPackage ../tools/system/mq-cli { }; + + nfdump = callPackage ../tools/networking/nfdump { }; + + nixpkgs-pytools = with python3.pkgs; toPythonApplication nixpkgs-pytools; + + noteshrink = callPackage ../tools/misc/noteshrink { }; + + noti = callPackage ../tools/misc/noti { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + + nrsc5 = callPackage ../applications/misc/nrsc5 { }; + + nwipe = callPackage ../tools/security/nwipe { }; + + nx-libs = callPackage ../tools/X11/nx-libs { }; + + nyx = callPackage ../tools/networking/nyx { }; + + ocrmypdf = callPackage ../tools/text/ocrmypdf { }; + + onboard = callPackage ../applications/misc/onboard { }; + + xkbd = callPackage ../applications/misc/xkbd { }; + + optar = callPackage ../tools/graphics/optar {}; + + patdiff = callPackage ../tools/misc/patdiff { }; + + pbpst = callPackage ../applications/misc/pbpst { }; + + pbzx = callPackage ../tools/compression/pbzx { }; + + persepolis = python3Packages.callPackage ../tools/networking/persepolis { }; + + pev = callPackage ../development/tools/analysis/pev { }; + + phoronix-test-suite = callPackage ../tools/misc/phoronix-test-suite { }; + + photon = callPackage ../tools/networking/photon { }; + + playerctl = callPackage ../tools/audio/playerctl { }; + + ps_mem = callPackage ../tools/system/ps_mem { }; + + psstop = callPackage ../tools/system/psstop { }; + + parallel-rust = callPackage ../tools/misc/parallel-rust { }; + + pyCA = python3Packages.callPackage ../applications/video/pyca {}; + + pyznap = python3Packages.callPackage ../tools/backup/pyznap {}; + + procs = callPackage ../tools/admin/procs { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + psrecord = python3Packages.callPackage ../tools/misc/psrecord {}; + + scour = with python3Packages; toPythonApplication scour; + + s2png = callPackage ../tools/graphics/s2png { }; + + shab = callPackage ../tools/text/shab { }; + + shell-hist = callPackage ../tools/misc/shell-hist { }; + + simg2img = callPackage ../tools/filesystems/simg2img { }; + + snipes = callPackage ../games/snipes { }; + + socklog = callPackage ../tools/system/socklog { }; + + staccato = callPackage ../tools/text/staccato { }; + + stagit = callPackage ../development/tools/stagit { }; + + bash-supergenpass = callPackage ../tools/security/bash-supergenpass { }; + + sweep-visualizer = callPackage ../tools/misc/sweep-visualizer { }; + + syscall_limiter = callPackage ../os-specific/linux/syscall_limiter {}; + + syslogng = callPackage ../tools/system/syslog-ng { }; + + syslogng_incubator = callPackage ../tools/system/syslog-ng-incubator { }; + + inherit (callPackages ../servers/rainloop { }) + rainloop-community + rainloop-standard; + + ring-daemon = callPackage ../applications/networking/instant-messengers/ring-daemon { }; + + riot-desktop = callPackage ../applications/networking/instant-messengers/riot/riot-desktop.nix { }; + + riot-web = callPackage ../applications/networking/instant-messengers/riot/riot-web.nix { + conf = config.riot-web.conf or null; + }; + + roundcube = callPackage ../servers/roundcube { }; + + roundcubePlugins = dontRecurseIntoAttrs (callPackage ../servers/roundcube/plugins { }); + + routinator = callPackage ../servers/routinator { }; + + rsbep = callPackage ../tools/backup/rsbep { }; + + rsyslog = callPackage ../tools/system/rsyslog { + hadoop = null; # Currently Broken + czmq = czmq3; + }; + + rsyslog-light = rsyslog.override { + libkrb5 = null; + systemd = null; + jemalloc = null; + mysql = null; + postgresql = null; + libdbi = null; + net_snmp = null; + libuuid = null; + gnutls = null; + libgcrypt = null; + liblognorm = null; + openssl = null; + librelp = null; + libgt = null; + libksi = null; + liblogging = null; + libnet = null; + hadoop = null; + rdkafka = null; + libmongo-client = null; + czmq = null; + rabbitmq-c = null; + hiredis = null; + }; + + mar1d = callPackage ../games/mar1d { } ; + + mcrypt = callPackage ../tools/misc/mcrypt { }; + + mongodb-compass = callPackage ../tools/misc/mongodb-compass { }; + + mongodb-tools = callPackage ../tools/misc/mongodb-tools { + # XXX: this is failing with Go 1.12. Error is related to cgo, an + # update to this package might fix it. + buildGoPackage = buildGo111Package; + }; + + moosefs = callPackage ../tools/filesystems/moosefs { }; + + mozlz4a = callPackage ../tools/compression/mozlz4a { }; + + msr-tools = callPackage ../os-specific/linux/msr-tools { }; + + mstflint = callPackage ../tools/misc/mstflint { }; + + mcelog = callPackage ../os-specific/linux/mcelog { + utillinux = utillinuxMinimal; + }; + + sqlint = callPackage ../development/tools/sqlint { }; + + antibody = callPackage ../shells/zsh/antibody { }; + + antigen = callPackage ../shells/zsh/antigen { }; + + apparix = callPackage ../tools/misc/apparix { }; + + appleseed = callPackage ../tools/graphics/appleseed { }; + + arping = callPackage ../tools/networking/arping { }; + + arpoison = callPackage ../tools/networking/arpoison { }; + + asciidoc = callPackage ../tools/typesetting/asciidoc { + inherit (python2Packages) matplotlib numpy aafigure recursivePthLoader; + w3m = w3m-batch; + enableStandardFeatures = false; + }; + + asciidoc-full = appendToName "full" (asciidoc.override { + inherit (python2Packages) pygments; + texlive = texlive.combine { inherit (texlive) scheme-minimal dvipng; }; + enableStandardFeatures = true; + }); + + asciidoc-full-with-plugins = appendToName "full-with-plugins" (asciidoc.override { + inherit (python2Packages) pygments; + texlive = texlive.combine { inherit (texlive) scheme-minimal dvipng; }; + enableStandardFeatures = true; + enableExtraPlugins = true; + }); + + asciidoctor = callPackage ../tools/typesetting/asciidoctor { + # kindlegen is unfree, don't enable by default + kindlegen = null; + # epubcheck pulls in Java, which is problematic on some platforms + epubcheck = null; + }; + + asunder = callPackage ../applications/audio/asunder { }; + + autossh = callPackage ../tools/networking/autossh { }; + + assh = callPackage ../tools/networking/assh { }; + + asynk = callPackage ../tools/networking/asynk { }; + + b2sum = callPackage ../tools/security/b2sum { + inherit (llvmPackages) openmp; + }; + + bacula = callPackage ../tools/backup/bacula { }; + + bareos = callPackage ../tools/backup/bareos { }; + + bats = callPackage ../development/interpreters/bats { }; + + bbe = callPackage ../tools/misc/bbe { }; + + bdsync = callPackage ../tools/backup/bdsync { }; + + beanstalkd = callPackage ../servers/beanstalkd { }; + + beegfs = callPackage ../os-specific/linux/beegfs { }; + + beets = callPackage ../tools/audio/beets { + pythonPackages = python3Packages; + }; + + bento4 = callPackage ../tools/video/bento4 { }; + + bepasty = callPackage ../tools/misc/bepasty { }; + + bettercap = callPackage ../tools/security/bettercap { }; + + bfg-repo-cleaner = gitAndTools.bfg-repo-cleaner; + + bfs = callPackage ../tools/system/bfs { }; + + bgs = callPackage ../tools/X11/bgs { }; + + biber = callPackage ../tools/typesetting/biber { }; + + birdfont = callPackage ../tools/misc/birdfont { }; + xmlbird = callPackage ../tools/misc/birdfont/xmlbird.nix { }; + + blastem = callPackage ../misc/emulators/blastem { + inherit (python27Packages) pillow; + }; + + blueman = callPackage ../tools/bluetooth/blueman { }; + + bmrsa = callPackage ../tools/security/bmrsa/11.nix { }; + + bogofilter = callPackage ../tools/misc/bogofilter { }; + + bsdbuild = callPackage ../development/tools/misc/bsdbuild { }; + + bsdiff = callPackage ../tools/compression/bsdiff { }; + + btar = callPackage ../tools/backup/btar { + librsync = librsync_0_9; + }; + + bud = callPackage ../tools/networking/bud { + inherit (pythonPackages) gyp; + }; + + bup = callPackage ../tools/backup/bup { }; + + burp = callPackage ../tools/backup/burp { }; + + buku = callPackage ../applications/misc/buku { }; + + byzanz = callPackage ../applications/video/byzanz {}; + + ori = callPackage ../tools/backup/ori { }; + + anydesk = callPackage ../applications/networking/remote/anydesk { }; + + atool = callPackage ../tools/archivers/atool { }; + + bsc = callPackage ../tools/compression/bsc { + inherit (llvmPackages) openmp; + }; + + bzip2 = callPackage ../tools/compression/bzip2 { }; + + cabextract = callPackage ../tools/archivers/cabextract { }; + + cadaver = callPackage ../tools/networking/cadaver { + openssl = openssl_1_0_2; + }; + + davix = callPackage ../tools/networking/davix { }; + + cantata = libsForQt5.callPackage ../applications/audio/cantata { + inherit vlc; + }; + + can-utils = callPackage ../os-specific/linux/can-utils { }; + + caudec = callPackage ../applications/audio/caudec { }; + + ccd2iso = callPackage ../tools/cd-dvd/ccd2iso { }; + + ccid = callPackage ../tools/security/ccid { }; + + ccrypt = callPackage ../tools/security/ccrypt { }; + + ccze = callPackage ../tools/misc/ccze { }; + + cdecl = callPackage ../development/tools/cdecl { }; + + cdi2iso = callPackage ../tools/cd-dvd/cdi2iso { }; + + cdimgtools = callPackage ../tools/cd-dvd/cdimgtools { }; + + cdrdao = callPackage ../tools/cd-dvd/cdrdao { }; + + cdrkit = callPackage ../tools/cd-dvd/cdrkit { }; + + mdf2iso = callPackage ../tools/cd-dvd/mdf2iso { }; + + nrg2iso = callPackage ../tools/cd-dvd/nrg2iso { }; + + libceph = ceph.lib; + ceph = callPackage ../tools/filesystems/ceph { + boost = boost166.override { enablePython = true; }; + }; + ceph-dev = ceph; + + inherit (callPackages ../tools/security/certmgr { }) + certmgr certmgr-selfsigned; + + cfdg = callPackage ../tools/graphics/cfdg { }; + + checkinstall = callPackage ../tools/package-management/checkinstall { }; + + chit = callPackage ../development/tools/chit { }; + + chkrootkit = callPackage ../tools/security/chkrootkit { }; + + chrony = callPackage ../tools/networking/chrony { }; + + chunkfs = callPackage ../tools/filesystems/chunkfs { }; + + chunksync = callPackage ../tools/backup/chunksync { }; + + cipherscan = callPackage ../tools/security/cipherscan { + openssl = if stdenv.hostPlatform.system == "x86_64-linux" + then openssl-chacha + else openssl; + }; + + cjdns = callPackage ../tools/networking/cjdns { }; + + cksfv = callPackage ../tools/networking/cksfv { }; + + clementine = libsForQt5.callPackage ../applications/audio/clementine { + gst_plugins = + with gst_all_1; [ gst-plugins-base gst-plugins-good gst-plugins-ugly gst-libav ]; + }; + + clementineUnfree = clementine.unfree; + + ciopfs = callPackage ../tools/filesystems/ciopfs { }; + + circleci-cli = callPackage ../development/tools/misc/circleci-cli { }; + + citrix_receiver_unwrapped = callPackage ../applications/networking/remote/citrix-receiver { }; + citrix_receiver_unwrapped_13_10_0 = citrix_receiver_unwrapped.override { version = "13.10.0"; }; + citrix_receiver_unwrapped_13_9_1 = citrix_receiver_unwrapped.override { version = "13.9.1"; }; + citrix_receiver_unwrapped_13_9_0 = citrix_receiver_unwrapped.override { version = "13.9.0"; }; + citrix_receiver_unwrapped_13_8_0 = citrix_receiver_unwrapped.override { version = "13.8.0"; }; + + citrix_receiver = callPackage ../applications/networking/remote/citrix-receiver/wrapper.nix { + citrix_receiver = citrix_receiver_unwrapped; + }; + citrix_receiver_13_10_0 = callPackage ../applications/networking/remote/citrix-receiver/wrapper.nix { + citrix_receiver = citrix_receiver_unwrapped_13_10_0; + }; + citrix_receiver_13_9_1 = callPackage ../applications/networking/remote/citrix-receiver/wrapper.nix { + citrix_receiver = citrix_receiver_unwrapped_13_9_1; + }; + citrix_receiver_13_9_0 = callPackage ../applications/networking/remote/citrix-receiver/wrapper.nix { + citrix_receiver = citrix_receiver_unwrapped_13_9_0; + }; + citrix_receiver_13_8_0 = callPackage ../applications/networking/remote/citrix-receiver/wrapper.nix { + citrix_receiver = citrix_receiver_unwrapped_13_8_0; + }; + + citrix_workspace_unwrapped = callPackage ../applications/networking/remote/citrix-workspace { }; + citrix_workspace_unwrapped_19_6_0 = citrix_workspace_unwrapped.override { version = "19.6.0"; }; + citrix_workspace_unwrapped_19_3_0 = citrix_workspace_unwrapped.override { version = "19.3.0"; }; + + citrix_workspace = callPackage ../applications/networking/remote/citrix-workspace/wrapper.nix { + citrix_workspace = citrix_workspace_unwrapped; + }; + citrix_workspace_19_6_0 = callPackage ../applications/networking/remote/citrix-workspace/wrapper.nix { + citrix_workspace = citrix_workspace_unwrapped_19_6_0; + }; + citrix_workspace_19_3_0 = callPackage ../applications/networking/remote/citrix-workspace/wrapper.nix { + citrix_workspace = citrix_workspace_unwrapped_19_3_0; + }; + + citra = libsForQt5.callPackage ../misc/emulators/citra { }; + + cmst = libsForQt5.callPackage ../tools/networking/cmst { }; + + codimd = callPackage ../servers/web-apps/codimd { + nodejs = nodejs-10_x; + yarn2nix = yarn2nix-moretea.override { + nodejs = nodejs-10_x; + yarn = yarn.override { nodejs = nodejs-10_x; }; + }; + }; + + colord = callPackage ../tools/misc/colord { }; + + colord-gtk = callPackage ../tools/misc/colord-gtk { }; + + colordiff = callPackage ../tools/text/colordiff { }; + + concurrencykit = callPackage ../development/libraries/concurrencykit { }; + + connect = callPackage ../tools/networking/connect { }; + + conspy = callPackage ../os-specific/linux/conspy {}; + + connman = callPackage ../tools/networking/connman { }; + + connman-gtk = callPackage ../tools/networking/connman/connman-gtk { }; + + connman-ncurses = callPackage ../tools/networking/connman/connman-ncurses { }; + + connman-notify = callPackage ../tools/networking/connman/connman-notify { }; + + connmanui = callPackage ../tools/networking/connman/connmanui { }; + + connman_dmenu = callPackage ../tools/networking/connman/connman_dmenu { }; + + convertlit = callPackage ../tools/text/convertlit { }; + + collectd = callPackage ../tools/system/collectd { + libsigrok = libsigrok-0-3-0; # not compatible with >= 0.4.0 yet + }; + + collectd-data = callPackage ../tools/system/collectd/data.nix { }; + + colormake = callPackage ../development/tools/build-managers/colormake { }; + + cpuminer = callPackage ../tools/misc/cpuminer { }; + + cpuminer-multi = callPackage ../tools/misc/cpuminer-multi { }; + + cryptpad = callPackage ../servers/web-apps/cryptpad { }; + + ethash = callPackage ../development/libraries/ethash { }; + + ethminer = callPackage ../tools/misc/ethminer { }; + + cuetools = callPackage ../tools/cd-dvd/cuetools { }; + + u3-tool = callPackage ../tools/filesystems/u3-tool { }; + + unifdef = callPackage ../development/tools/misc/unifdef { }; + + unionfs-fuse = callPackage ../tools/filesystems/unionfs-fuse { }; + + usb-modeswitch = callPackage ../development/tools/misc/usb-modeswitch { }; + usb-modeswitch-data = callPackage ../development/tools/misc/usb-modeswitch/data.nix { }; + + anthy = callPackage ../tools/inputmethods/anthy { }; + + libpinyin = callPackage ../development/libraries/libpinyin { }; + + libskk = callPackage ../development/libraries/libskk { + inherit (gnome3) gnome-common; + }; + + m17n_db = callPackage ../tools/inputmethods/m17n-db { }; + + m17n_lib = callPackage ../tools/inputmethods/m17n-lib { }; + + libotf = callPackage ../tools/inputmethods/m17n-lib/otf.nix { + inherit (xorg) libXaw; + }; + + skktools = callPackage ../tools/inputmethods/skk/skktools { }; + skk-dicts = callPackage ../tools/inputmethods/skk/skk-dicts { }; + + libkkc-data = callPackage ../data/misc/libkkc-data { + inherit (pythonPackages) marisa; + }; + + libkkc = callPackage ../tools/inputmethods/libkkc { }; + + ibus = callPackage ../tools/inputmethods/ibus { + inherit (gnome3) dconf; + }; + + ibus-qt = callPackage ../tools/inputmethods/ibus/ibus-qt.nix { }; + + ibus-engines = recurseIntoAttrs { + anthy = callPackage ../tools/inputmethods/ibus-engines/ibus-anthy { }; + + hangul = callPackage ../tools/inputmethods/ibus-engines/ibus-hangul { }; + + kkc = callPackage ../tools/inputmethods/ibus-engines/ibus-kkc { }; + + libpinyin = callPackage ../tools/inputmethods/ibus-engines/ibus-libpinyin { }; + + m17n = callPackage ../tools/inputmethods/ibus-engines/ibus-m17n { }; + + mozc = callPackage ../tools/inputmethods/ibus-engines/ibus-mozc rec { + python = python2; + inherit (python2Packages) gyp; + protobuf = pkgs.protobuf.overrideDerivation (oldAttrs: { stdenv = clangStdenv; }); + }; + + table = callPackage ../tools/inputmethods/ibus-engines/ibus-table { + inherit (gnome3) dconf; + }; + + table-chinese = callPackage ../tools/inputmethods/ibus-engines/ibus-table-chinese { + ibus-table = ibus-engines.table; + }; + + table-others = callPackage ../tools/inputmethods/ibus-engines/ibus-table-others { + ibus-table = ibus-engines.table; + }; + + uniemoji = callPackage ../tools/inputmethods/ibus-engines/ibus-uniemoji { }; + + typing-booster-unwrapped = callPackage ../tools/inputmethods/ibus-engines/ibus-typing-booster { }; + + typing-booster = callPackage ../tools/inputmethods/ibus-engines/ibus-typing-booster/wrapper.nix { + typing-booster = ibus-engines.typing-booster-unwrapped; + }; + }; + + ibus-with-plugins = callPackage ../tools/inputmethods/ibus/wrapper.nix { + inherit (gnome3) dconf; + }; + + interception-tools = callPackage ../tools/inputmethods/interception-tools { }; + interception-tools-plugins = { + caps2esc = callPackage ../tools/inputmethods/interception-tools/caps2esc.nix { }; + }; + + brotli = callPackage ../tools/compression/brotli { }; + + biosdevname = callPackage ../tools/networking/biosdevname { }; + + c14 = callPackage ../applications/networking/c14 { }; + + certstrap = callPackage ../tools/security/certstrap { }; + + cfssl = callPackage ../tools/security/cfssl { }; + + chafa = callPackage ../tools/misc/chafa { }; + + checkbashisms = callPackage ../development/tools/misc/checkbashisms { }; + + civetweb = callPackage ../development/libraries/civetweb { }; + + ckb-next = libsForQt5.callPackage ../tools/misc/ckb-next { }; + + clamav = callPackage ../tools/security/clamav { }; + + clex = callPackage ../tools/misc/clex { }; + + client-ip-echo = callPackage ../servers/misc/client-ip-echo { }; + + cloc = callPackage ../tools/misc/cloc { }; + + cloog = callPackage ../development/libraries/cloog { + isl = isl_0_14; + }; + + cloog_0_18_0 = callPackage ../development/libraries/cloog/0.18.0.nix { + isl = isl_0_11; + }; + + cloogppl = callPackage ../development/libraries/cloog-ppl { }; + + cloud-utils = callPackage ../tools/misc/cloud-utils { }; + + cocoapods = callPackage ../development/mobile/cocoapods { }; + + cocoapods-beta = lowPrio (callPackage ../development/mobile/cocoapods { beta = true; }); + + compass = callPackage ../development/tools/compass { }; + + conda = callPackage ../tools/package-management/conda { }; + + convmv = callPackage ../tools/misc/convmv { }; + + convoy = callPackage ../tools/filesystems/convoy { }; + + cpcfs = callPackage ../tools/filesystems/cpcfs { }; + + cool-retro-term = libsForQt5.callPackage ../applications/misc/cool-retro-term { }; + + coreutils = callPackage ../tools/misc/coreutils { }; + coreutils-full = coreutils.override { minimal = false; }; + coreutils-prefixed = coreutils.override { withPrefix = true; singleBinary = false; }; + + corkscrew = callPackage ../tools/networking/corkscrew { }; + + cowpatty = callPackage ../tools/security/cowpatty { }; + + cpio = callPackage ../tools/archivers/cpio { }; + + crackxls = callPackage ../tools/security/crackxls { }; + + create-cycle-app = nodePackages.create-cycle-app; + + createrepo_c = callPackage ../tools/package-management/createrepo_c { }; + + cromfs = callPackage ../tools/archivers/cromfs { }; + + cron = callPackage ../tools/system/cron { }; + + inherit (callPackages ../development/compilers/cudatoolkit { }) + cudatoolkit_6 + cudatoolkit_6_5 + cudatoolkit_7 + cudatoolkit_7_5 + cudatoolkit_8 + cudatoolkit_9 + cudatoolkit_9_0 + cudatoolkit_9_1 + cudatoolkit_9_2 + cudatoolkit_10 + cudatoolkit_10_0; + + cudatoolkit = cudatoolkit_9; + + inherit (callPackages ../development/libraries/science/math/cudnn { }) + cudnn_cudatoolkit_7 + cudnn_cudatoolkit_7_5 + cudnn6_cudatoolkit_8 + cudnn_cudatoolkit_8 + cudnn_cudatoolkit_9 + cudnn_cudatoolkit_9_0 + cudnn_cudatoolkit_9_1 + cudnn_cudatoolkit_9_2 + cudnn_cudatoolkit_10 + cudnn_cudatoolkit_10_0; + + cudnn = cudnn_cudatoolkit_9; + + curlFull = curl.override { + idnSupport = true; + ldapSupport = true; + gssSupport = true; + brotliSupport = true; + }; + + curl = callPackage ../tools/networking/curl { }; + + curl_unix_socket = callPackage ../tools/networking/curl-unix-socket rec { }; + + curlie = callPackage ../tools/networking/curlie { }; + + cunit = callPackage ../tools/misc/cunit { }; + bcunit = callPackage ../tools/misc/bcunit { }; + + curlftpfs = callPackage ../tools/filesystems/curlftpfs { }; + + cutter = callPackage ../tools/networking/cutter { }; + + cwebbin = callPackage ../development/tools/misc/cwebbin { }; + + cvs_fast_export = callPackage ../applications/version-management/cvs-fast-export { }; + + dadadodo = callPackage ../tools/text/dadadodo { }; + + daemonize = callPackage ../tools/system/daemonize { }; + + daq = callPackage ../applications/networking/ids/daq { }; + + dar = callPackage ../tools/backup/dar { }; + + darkhttpd = callPackage ../servers/http/darkhttpd { }; + + darkstat = callPackage ../tools/networking/darkstat { }; + + dav1d = callPackage ../development/libraries/dav1d { }; + + davfs2 = callPackage ../tools/filesystems/davfs2 { }; + + dbeaver = callPackage ../applications/misc/dbeaver { + jdk = jdk11; + }; + + dbench = callPackage ../development/tools/misc/dbench { }; + + dclxvi = callPackage ../development/libraries/dclxvi { }; + + dcraw = callPackage ../tools/graphics/dcraw { }; + + dcfldd = callPackage ../tools/system/dcfldd { }; + + debianutils = callPackage ../tools/misc/debianutils { }; + + debian-devscripts = callPackage ../tools/misc/debian-devscripts { }; + + debootstrap = callPackage ../tools/misc/debootstrap { }; + + deer = callPackage ../shells/zsh/zsh-deer { }; + + detox = callPackage ../tools/misc/detox { }; + + devilspie2 = callPackage ../applications/misc/devilspie2 { + gtk = gtk3; + }; + + dex = callPackage ../tools/X11/dex { }; + + ddccontrol = callPackage ../tools/misc/ddccontrol { }; + + ddccontrol-db = callPackage ../data/misc/ddccontrol-db { }; + + ddcutil = callPackage ../tools/misc/ddcutil { }; + + ddclient = callPackage ../tools/networking/ddclient { }; + + dd_rescue = callPackage ../tools/system/dd_rescue { }; + + ddrescue = callPackage ../tools/system/ddrescue { }; + + ddrescueview = callPackage ../tools/system/ddrescueview { }; + + ddrutility = callPackage ../tools/system/ddrutility { }; + + deluge = callPackage ../applications/networking/p2p/deluge { + pythonPackages = python2Packages; + }; + + desktop-file-utils = callPackage ../tools/misc/desktop-file-utils { }; + + dfc = callPackage ../tools/system/dfc { }; + + dev86 = callPackage ../development/compilers/dev86 { }; + + diskrsync = callPackage ../tools/backup/diskrsync { + buildGoPackage = buildGo110Package; + }; + + djbdns = callPackage ../tools/networking/djbdns { }; + + dnscrypt-proxy = callPackage ../tools/networking/dnscrypt-proxy/1.x { }; + + dnscrypt-proxy2 = callPackage ../tools/networking/dnscrypt-proxy/2.x { + buildGoPackage = buildGo110Package; + }; + + dnscrypt-wrapper = callPackage ../tools/networking/dnscrypt-wrapper { }; + + dnsenum = callPackage ../tools/security/dnsenum { }; + + dnsmasq = callPackage ../tools/networking/dnsmasq { }; + + dnsperf = callPackage ../tools/networking/dnsperf { }; + + dnsrecon = callPackage ../tools/security/dnsrecon { }; + + dnstop = callPackage ../tools/networking/dnstop { }; + + dhcp = callPackage ../tools/networking/dhcp { }; + + dhcpdump = callPackage ../tools/networking/dhcpdump { }; + + dhcpcd = callPackage ../tools/networking/dhcpcd { }; + + dhcping = callPackage ../tools/networking/dhcping { }; + + di = callPackage ../tools/system/di { }; + + diction = callPackage ../tools/text/diction { }; + + diffoscope = callPackage ../tools/misc/diffoscope { + jdk = jdk8; + }; + + diffstat = callPackage ../tools/text/diffstat { }; + + diffutils = callPackage ../tools/text/diffutils { }; + + dir2opus = callPackage ../tools/audio/dir2opus { + inherit (pythonPackages) mutagen python wrapPython; + }; + + picotts = callPackage ../tools/audio/picotts { }; + + wgetpaste = callPackage ../tools/text/wgetpaste { }; + + dirmngr = callPackage ../tools/security/dirmngr { }; + + dirvish = callPackage ../tools/backup/dirvish { }; + + disper = callPackage ../tools/misc/disper { }; + + dleyna-connector-dbus = callPackage ../development/libraries/dleyna-connector-dbus { }; + + dleyna-core = callPackage ../development/libraries/dleyna-core { }; + + dleyna-renderer = callPackage ../development/libraries/dleyna-renderer { }; + + dleyna-server = callPackage ../development/libraries/dleyna-server { }; + + dmd = callPackage ../development/compilers/dmd { }; + + dmg2img = callPackage ../tools/misc/dmg2img { + openssl = openssl_1_0_2; + }; + + docbook2odf = callPackage ../tools/typesetting/docbook2odf { }; + + doas = callPackage ../tools/security/doas { }; + + docbook2x = callPackage ../tools/typesetting/docbook2x { }; + + docbook2mdoc = callPackage ../tools/misc/docbook2mdoc { }; + + docear = callPackage ../applications/office/docear { }; + + dockbarx = callPackage ../applications/misc/dockbarx { }; + + dog = callPackage ../tools/system/dog { }; + + dosfstools = callPackage ../tools/filesystems/dosfstools { }; + + dotnetfx35 = callPackage ../development/libraries/dotnetfx35 { }; + + dotnetfx40 = callPackage ../development/libraries/dotnetfx40 { }; + + dolphinEmu = callPackage ../misc/emulators/dolphin-emu { }; + dolphinEmuMaster = qt5.callPackage ../misc/emulators/dolphin-emu/master.nix { + inherit (darwin.apple_sdk.frameworks) CoreBluetooth ForceFeedback IOKit OpenGL; + }; + + doomseeker = qt5.callPackage ../applications/misc/doomseeker { }; + + doom-bcc = callPackage ../games/zdoom/bcc-git.nix { }; + + slade = callPackage ../applications/misc/slade { + wxGTK = wxGTK30; + }; + + sladeUnstable = callPackage ../applications/misc/slade/git.nix { + wxGTK = wxGTK30; + }; + + drive = callPackage ../applications/networking/drive { }; + + driftnet = callPackage ../tools/networking/driftnet {}; + + drone = callPackage ../development/tools/continuous-integration/drone { }; + + drone-cli = callPackage ../development/tools/continuous-integration/drone-cli { }; + + dropbear = callPackage ../tools/networking/dropbear { }; + + dsview = libsForQt5.callPackage ../applications/science/electronics/dsview { }; + + dtach = callPackage ../tools/misc/dtach { }; + + dtc = callPackage ../development/compilers/dtc { }; + + dub = callPackage ../development/tools/build-managers/dub { }; + + duc = callPackage ../tools/misc/duc { }; + + duff = callPackage ../tools/filesystems/duff { }; + + dumptorrent = callPackage ../tools/misc/dumptorrent { }; + + duo-unix = callPackage ../tools/security/duo-unix { }; + + duplicacy = callPackage ../tools/backup/duplicacy { }; + + duplicati = callPackage ../tools/backup/duplicati { }; + + duplicity = callPackage ../tools/backup/duplicity { + gnupg = gnupg1; + }; + + duply = callPackage ../tools/backup/duply { }; + + dvd-vr = callPackage ../tools/cd-dvd/dvd-vr { }; + + dvdisaster = callPackage ../tools/cd-dvd/dvdisaster { }; + + dvdplusrwtools = callPackage ../tools/cd-dvd/dvd+rw-tools { }; + + dvgrab = callPackage ../tools/video/dvgrab { }; + + dvtm = callPackage ../tools/misc/dvtm { + # if you prefer a custom config, write the config.h in dvtm.config.h + # and enable + # customConfig = builtins.readFile ./dvtm.config.h; + }; + + dvtm-unstable = callPackage ../tools/misc/dvtm/unstable.nix {}; + + ecmtools = callPackage ../tools/cd-dvd/ecm-tools { }; + + e2tools = callPackage ../tools/filesystems/e2tools { }; + + e2fsprogs = callPackage ../tools/filesystems/e2fsprogs { }; + + easyrsa = callPackage ../tools/networking/easyrsa { }; + + easyrsa2 = callPackage ../tools/networking/easyrsa/2.x.nix { }; + + easysnap = callPackage ../tools/backup/easysnap { }; + + ebook_tools = callPackage ../tools/text/ebook-tools { }; + + ecryptfs = callPackage ../tools/security/ecryptfs { }; + + ecryptfs-helper = callPackage ../tools/security/ecryptfs/helper.nix { }; + + edid-decode = callPackage ../tools/misc/edid-decode { }; + + editres = callPackage ../tools/graphics/editres { }; + + edit = callPackage ../applications/editors/edit { }; + + edk2 = callPackage ../development/compilers/edk2 { }; + + eff = callPackage ../development/interpreters/eff { }; + + eflite = callPackage ../applications/audio/eflite {}; + + eid-mw = callPackage ../tools/security/eid-mw { }; + + epubcheck = callPackage ../tools/text/epubcheck { }; + + mcrcon = callPackage ../tools/networking/mcrcon {}; + + s-tar = callPackage ../tools/archivers/s-tar {}; + + sonota = callPackage ../tools/misc/sonota { }; + + sonobuoy = callPackage ../applications/networking/cluster/sonobuoy { }; + + tealdeer = callPackage ../tools/misc/tealdeer { }; + + teamocil = callPackage ../tools/misc/teamocil { }; + + tsm-client = callPackage ../tools/backup/tsm-client { jdk8 = null; }; + tsm-client-withGui = callPackage ../tools/backup/tsm-client { }; + + tracker = callPackage ../development/libraries/tracker { }; + + tracker-miners = callPackage ../development/libraries/tracker-miners { }; + + tridactyl-native = callPackage ../tools/networking/tridactyl-native { }; + + trompeloeil = callPackage ../development/libraries/trompeloeil { }; + + uudeview = callPackage ../tools/misc/uudeview { }; + + uutils-coreutils = callPackage ../tools/misc/uutils-coreutils { + inherit (pythonPackages) sphinx; + }; + + wallutils = callPackage ../tools/graphics/wallutils { }; + + wl-clipboard = callPackage ../tools/misc/wl-clipboard { }; + + z-lua = callPackage ../tools/misc/z-lua { }; + + zabbix-cli = callPackage ../tools/misc/zabbix-cli { }; + + zabbixctl = callPackage ../tools/misc/zabbixctl { }; + + zzuf = callPackage ../tools/security/zzuf { }; + + ### DEVELOPMENT / EMSCRIPTEN + + buildEmscriptenPackage = callPackage ../development/em-modules/generic { }; + + carp = callPackage ../development/compilers/carp { }; + + cholmod-extra = callPackage ../development/libraries/science/math/cholmod-extra { }; + + emscriptenVersion = "1.38.28"; + + emscripten = callPackage ../development/compilers/emscripten { }; + + emscriptenfastcompPackages = dontRecurseIntoAttrs (callPackage ../development/compilers/emscripten/fastcomp { }); + + emscriptenfastcomp = emscriptenfastcompPackages.emscriptenfastcomp; + + emscriptenPackages = recurseIntoAttrs (callPackage ./emscripten-packages.nix { }); + + emscriptenStdenv = stdenv // { mkDerivation = buildEmscriptenPackage; }; + + efibootmgr = callPackage ../tools/system/efibootmgr { }; + + efivar = callPackage ../tools/system/efivar { }; + + evemu = callPackage ../tools/system/evemu { }; + + # The latest version used by elasticsearch, logstash, kibana and the the beats from elastic. + elk5Version = "5.6.16"; + elk6Version = "6.7.2"; + elk7Version = "7.0.1"; + + elasticsearch5 = callPackage ../servers/search/elasticsearch/5.x.nix { + utillinux = utillinuxMinimal; + }; + elasticsearch6 = callPackage ../servers/search/elasticsearch/6.x.nix { + utillinux = utillinuxMinimal; + }; + elasticsearch6-oss = callPackage ../servers/search/elasticsearch/6.x.nix { + enableUnfree = false; + utillinux = utillinuxMinimal; + }; + elasticsearch7 = callPackage ../servers/search/elasticsearch/7.x.nix { + utillinux = utillinuxMinimal; + }; + elasticsearch7-oss = callPackage ../servers/search/elasticsearch/7.x.nix { + enableUnfree = false; + utillinux = utillinuxMinimal; + }; + elasticsearch = elasticsearch6; + elasticsearch-oss = elasticsearch6-oss; + + elasticsearchPlugins = recurseIntoAttrs ( + callPackage ../servers/search/elasticsearch/plugins.nix { + elasticsearch = elasticsearch-oss; + } + ); + elasticsearch5Plugins = elasticsearchPlugins.override { + elasticsearch = elasticsearch5; + }; + elasticsearch6Plugins = elasticsearchPlugins.override { + elasticsearch = elasticsearch6-oss; + }; + elasticsearch7Plugins = elasticsearchPlugins.override { + elasticsearch = elasticsearch7-oss; + }; + + elasticsearch-curator = with (python3.override { + packageOverrides = self: super: { + click = super.click.overridePythonAttrs (oldAttrs: rec { + version = "6.7"; + src = oldAttrs.src.override { + inherit version; + sha256 = "f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"; + }; + }); + pyyaml = super.pyyaml.overridePythonAttrs (oldAttrs: rec { + version = "3.12"; + src = oldAttrs.src.override { + inherit version; + sha256 = "1aqjl8dk9amd4zr99n8v2qxzgmr2hdvqfma4zh7a41rj6336c9sr"; + }; + }); + }; + }).pkgs; toPythonApplication elasticsearch-curator; + + embree2 = callPackage ../development/libraries/embree/2.x.nix { }; + + emem = callPackage ../applications/misc/emem { }; + + emv = callPackage ../tools/misc/emv { }; + + enblend-enfuse = callPackage ../tools/graphics/enblend-enfuse { }; + + endlessh = callPackage ../servers/endlessh { }; + + cryfs = callPackage ../tools/filesystems/cryfs { + spdlog = spdlog_0; + }; + + encfs = callPackage ../tools/filesystems/encfs { + tinyxml2 = tinyxml-2; + }; + + enscript = callPackage ../tools/text/enscript { }; + + entr = callPackage ../tools/misc/entr { }; + + envoy = callPackage ../tools/networking/envoy { + bazel = bazel_0_4; + }; + + eot_utilities = callPackage ../tools/misc/eot-utilities { }; + + eplot = callPackage ../tools/graphics/eplot { }; + + epstool = callPackage ../tools/graphics/epstool { }; + + epsxe = callPackage ../misc/emulators/epsxe { }; + + escrotum = callPackage ../tools/graphics/escrotum { + inherit (pythonPackages) buildPythonApplication pygtk numpy; + }; + + ethtool = callPackage ../tools/misc/ethtool { }; + + ettercap = callPackage ../applications/networking/sniffers/ettercap { + openssl = openssl_1_0_2; + }; + + euca2ools = callPackage ../tools/virtualization/euca2ools { }; + + eventstat = callPackage ../os-specific/linux/eventstat { }; + + evtest = callPackage ../applications/misc/evtest { }; + + evtest-qt = libsForQt5.callPackage ../applications/misc/evtest-qt { }; + + exa = callPackage ../tools/misc/exa { }; + + exempi = callPackage ../development/libraries/exempi { + stdenv = if stdenv.isi686 then gcc6Stdenv else stdenv; + }; + + execline = skawarePackages.execline; + + executor = with python3Packages; toPythonApplication executor; + + exif = callPackage ../tools/graphics/exif { }; + + exiftags = callPackage ../tools/graphics/exiftags { }; + + exiftool = perlPackages.ImageExifTool; + + exodus = callPackage ../applications/altcoins/exodus { }; + + ext4magic = callPackage ../tools/filesystems/ext4magic { }; + + extract_url = callPackage ../applications/misc/extract_url { }; + + extundelete = callPackage ../tools/filesystems/extundelete { }; + + expect = callPackage ../tools/misc/expect { }; + + f2fs-tools = callPackage ../tools/filesystems/f2fs-tools { }; + + Fabric = python2Packages.Fabric; + + fail2ban = callPackage ../tools/security/fail2ban { }; + + fakeroot = callPackage ../tools/system/fakeroot { }; + + fakeroute = callPackage ../tools/networking/fakeroute { }; + + fakechroot = callPackage ../tools/system/fakechroot { }; + + fast-neural-doodle = callPackage ../tools/graphics/fast-neural-doodle { + inherit (python27Packages) numpy scipy h5py scikitlearn python + pillow; + }; + + fastpbkdf2 = callPackage ../development/libraries/fastpbkdf2 { }; + + fanficfare = callPackage ../tools/text/fanficfare { }; + + fastd = callPackage ../tools/networking/fastd { }; + + fatsort = callPackage ../tools/filesystems/fatsort { }; + + fcitx = callPackage ../tools/inputmethods/fcitx { + plugins = []; + }; + + fcitx-engines = recurseIntoAttrs { + + anthy = callPackage ../tools/inputmethods/fcitx-engines/fcitx-anthy { }; + + chewing = callPackage ../tools/inputmethods/fcitx-engines/fcitx-chewing { }; + + hangul = callPackage ../tools/inputmethods/fcitx-engines/fcitx-hangul { }; + + unikey = callPackage ../tools/inputmethods/fcitx-engines/fcitx-unikey { }; + + rime = callPackage ../tools/inputmethods/fcitx-engines/fcitx-rime { }; + + m17n = callPackage ../tools/inputmethods/fcitx-engines/fcitx-m17n { }; + + mozc = callPackage ../tools/inputmethods/fcitx-engines/fcitx-mozc rec { + python = python2; + inherit (python2Packages) gyp; + protobuf = pkgs.protobuf3_6.overrideDerivation (oldAttrs: { stdenv = clangStdenv; }); + }; + + table-extra = callPackage ../tools/inputmethods/fcitx-engines/fcitx-table-extra { }; + + table-other = callPackage ../tools/inputmethods/fcitx-engines/fcitx-table-other { }; + + cloudpinyin = callPackage ../tools/inputmethods/fcitx-engines/fcitx-cloudpinyin { }; + + libpinyin = libsForQt5.callPackage ../tools/inputmethods/fcitx-engines/fcitx-libpinyin { }; + + skk = callPackage ../tools/inputmethods/fcitx-engines/fcitx-skk { }; + }; + + fcitx-configtool = callPackage ../tools/inputmethods/fcitx/fcitx-configtool.nix { }; + + fcppt = callPackage ../development/libraries/fcppt { + stdenv = gcc8Stdenv; + }; + + fcrackzip = callPackage ../tools/security/fcrackzip { }; + + fcron = callPackage ../tools/system/fcron { }; + + fdm = callPackage ../tools/networking/fdm {}; + + featherpad = callPackage ../applications/editors/featherpad {}; + + feedreader = callPackage ../applications/networking/feedreaders/feedreader {}; + + ferm = callPackage ../tools/networking/ferm { }; + + ffsend = callPackage ../tools/misc/ffsend { }; + + fgallery = callPackage ../tools/graphics/fgallery { }; + + flannel = callPackage ../tools/networking/flannel { }; + + flare = callPackage ../games/flare { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + + flashbench = callPackage ../os-specific/linux/flashbench { }; + + flatpak = callPackage ../development/libraries/flatpak { }; + + flatpak-builder = callPackage ../development/tools/flatpak-builder { }; + + fltrdr = callPackage ../tools/misc/fltrdr { + stdenv = gcc8Stdenv; + icu = icu63; + }; + + fluent-bit = callPackage ../tools/misc/fluent-bit { + stdenv = gccStdenv; + }; + + flux = callPackage ../development/compilers/flux { }; + + fierce = callPackage ../tools/security/fierce { }; + + figlet = callPackage ../tools/misc/figlet { }; + + file = callPackage ../tools/misc/file { + inherit (windows) libgnurx; + }; + + filegive = callPackage ../tools/networking/filegive { }; + + fileschanged = callPackage ../tools/misc/fileschanged { }; + + filet = callPackage ../applications/misc/filet { }; + + findutils = callPackage ../tools/misc/findutils { }; + + finger_bsd = callPackage ../tools/networking/bsd-finger { }; + + iprange = callPackage ../applications/networking/firehol/iprange.nix {}; + + firehol = callPackage ../applications/networking/firehol {}; + + fio = callPackage ../tools/system/fio { }; + + firebird-emu = libsForQt5.callPackage ../misc/emulators/firebird-emu { }; + + flamerobin = callPackage ../applications/misc/flamerobin { }; + + flashtool = pkgsi686Linux.callPackage ../development/mobile/flashtool { + inherit (androidenv.androidPkgs_9_0) platform-tools; + }; + + flashrom = callPackage ../tools/misc/flashrom { }; + + flent = python3Packages.callPackage ../applications/networking/flent { }; + + flpsed = callPackage ../applications/editors/flpsed { }; + + fluentd = callPackage ../tools/misc/fluentd { }; + + flvstreamer = callPackage ../tools/networking/flvstreamer { }; + + hmetis = pkgsi686Linux.callPackage ../applications/science/math/hmetis { }; + + libbsd = callPackage ../development/libraries/libbsd { }; + + libbladeRF = callPackage ../development/libraries/libbladeRF { }; + + lp_solve = callPackage ../applications/science/math/lp_solve { }; + + lprof = callPackage ../tools/graphics/lprof { }; + + fastlane = callPackage ../tools/admin/fastlane { }; + + fatresize = callPackage ../tools/filesystems/fatresize {}; + + fdk_aac = callPackage ../development/libraries/fdk-aac { }; + + feedgnuplot = callPackage ../tools/graphics/feedgnuplot { }; + + fbv = callPackage ../tools/graphics/fbv { }; + + fim = callPackage ../tools/graphics/fim { }; + + flac123 = callPackage ../applications/audio/flac123 { }; + + flamegraph = callPackage ../development/tools/flamegraph { }; + + flvtool2 = callPackage ../tools/video/flvtool2 { }; + + fmbt = callPackage ../development/tools/fmbt { + python = python2; + }; + + fontforge = lowPrio (callPackage ../tools/misc/fontforge { + inherit (darwin.apple_sdk.frameworks) Carbon Cocoa; + }); + fontforge-gtk = fontforge.override { + withSpiro = true; + withGTK = true; + gtk2 = gtk2-x11; + inherit (darwin.apple_sdk.frameworks) Carbon Cocoa; + }; + + fontforge-fonttools = callPackage ../tools/misc/fontforge/fontforge-fonttools.nix {}; + + fontmatrix = callPackage ../applications/graphics/fontmatrix {}; + + foremost = callPackage ../tools/system/foremost { }; + + forktty = callPackage ../os-specific/linux/forktty {}; + + fortune = callPackage ../tools/misc/fortune { }; + + fox = callPackage ../development/libraries/fox { + libpng = libpng12; + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + fox_1_6 = callPackage ../development/libraries/fox/fox-1.6.nix { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + fpart = callPackage ../tools/misc/fpart { }; + + fping = callPackage ../tools/networking/fping {}; + + fpm = callPackage ../tools/package-management/fpm { }; + + fprot = callPackage ../tools/security/fprot { }; + + fprintd = callPackage ../tools/security/fprintd { }; + fprintd-thinkpad = fprintd.override { + thinkpad = true; + }; + + franz = callPackage ../applications/networking/instant-messengers/franz { }; + + freedroidrpg = callPackage ../games/freedroidrpg { }; + + freebind = callPackage ../tools/networking/freebind { }; + + freeipmi = callPackage ../tools/system/freeipmi {}; + + freetalk = callPackage ../applications/networking/instant-messengers/freetalk { + guile = guile_2_0; + }; + + freetds = callPackage ../development/libraries/freetds { }; + + frescobaldi = callPackage ../misc/frescobaldi {}; + + frostwire = callPackage ../applications/networking/p2p/frostwire { }; + frostwire-bin = callPackage ../applications/networking/p2p/frostwire/frostwire-bin.nix { }; + + ftgl = callPackage ../development/libraries/ftgl { + inherit (darwin.apple_sdk.frameworks) OpenGL; + }; + + ftop = callPackage ../os-specific/linux/ftop { }; + + fsarchiver = callPackage ../tools/archivers/fsarchiver { }; + + fsfs = callPackage ../tools/filesystems/fsfs { }; + + fstl = qt5.callPackage ../applications/graphics/fstl { }; + + fswebcam = callPackage ../os-specific/linux/fswebcam { }; + + fuseiso = callPackage ../tools/filesystems/fuseiso { }; + + fusuma = callPackage ../tools/inputmethods/fusuma {}; + + fdbPackages = dontRecurseIntoAttrs (callPackage ../servers/foundationdb { + stdenv49 = gcc49Stdenv; + }); + + inherit (fdbPackages) + foundationdb51 + foundationdb52 + foundationdb60 + foundationdb61 + ; + + foundationdb = foundationdb61; + + fuse-7z-ng = callPackage ../tools/filesystems/fuse-7z-ng { }; + + fuse-overlayfs = callPackage ../tools/filesystems/fuse-overlayfs {}; + + fusee-launcher = callPackage ../development/tools/fusee-launcher { }; + + fwknop = callPackage ../tools/security/fwknop { }; + + exfat = callPackage ../tools/filesystems/exfat { }; + + dos2unix = callPackage ../tools/text/dos2unix { }; + + uni2ascii = callPackage ../tools/text/uni2ascii { }; + + galculator = callPackage ../applications/misc/galculator { + gtk = gtk3; + }; + + galen = callPackage ../development/tools/galen {}; + + gallery-dl = callPackage ../applications/misc/gallery-dl { }; + + gandi-cli = callPackage ../tools/networking/gandi-cli { }; + + gandom-fonts = callPackage ../data/fonts/gandom-fonts { }; + + garmin-plugin = callPackage ../applications/misc/garmin-plugin {}; + + garmintools = callPackage ../development/libraries/garmintools {}; + + gauge = callPackage ../development/tools/gauge { }; + + gawk = callPackage ../tools/text/gawk { + inherit (darwin) locale; + }; + + gawkInteractive = appendToName "interactive" + (gawk.override { interactive = true; }); + + gawp = callPackage ../tools/misc/gawp { }; + + gazeboSimulator = recurseIntoAttrs rec { + sdformat = gazeboSimulator.sdformat4; + + sdformat3 = callPackage ../development/libraries/sdformat/3.nix { }; + + sdformat4 = callPackage ../development/libraries/sdformat { }; + + gazebo6 = callPackage ../applications/science/robotics/gazebo/6.nix { boost = boost160; }; + + gazebo6-headless = gazebo6.override { withHeadless = true; }; + + gazebo7 = callPackage ../applications/science/robotics/gazebo { }; + + gazebo7-headless = gazebo7.override { withHeadless = true; }; + + }; + + # at present, Gazebo 7.0.0 does not match Gazebo 6.5.1 for compatibility + gazebo = gazeboSimulator.gazebo6; + + gazebo-headless = gazeboSimulator.gazebo6-headless; + + gbdfed = callPackage ../tools/misc/gbdfed { + gtk = gtk2-x11; + }; + + gdmap = callPackage ../tools/system/gdmap { }; + + gelasio = callPackage ../data/fonts/gelasio { }; + + gen-oath-safe = callPackage ../tools/security/gen-oath-safe { }; + + genext2fs = callPackage ../tools/filesystems/genext2fs { }; + + gengetopt = callPackage ../development/tools/misc/gengetopt { }; + + genimage = callPackage ../tools/filesystems/genimage { }; + + gerrit = callPackage ../applications/version-management/gerrit { }; + + geteltorito = callPackage ../tools/misc/geteltorito { }; + + getmail = callPackage ../tools/networking/getmail { }; + + getopt = callPackage ../tools/misc/getopt { }; + + gexiv2 = callPackage ../development/libraries/gexiv2 { }; + + gftp = callPackage ../tools/networking/gftp { }; + + gfbgraph = callPackage ../development/libraries/gfbgraph { }; + + ggobi = callPackage ../tools/graphics/ggobi { }; + + gibo = callPackage ../tools/misc/gibo { }; + + gifsicle = callPackage ../tools/graphics/gifsicle { }; + + gifski = callPackage ../tools/graphics/gifski { }; + + git-big-picture = callPackage ../applications/version-management/git-and-tools/git-big-picture { }; + + git-crecord = callPackage ../applications/version-management/git-crecord { }; + + git-lfs = lowPrio (callPackage ../applications/version-management/git-lfs { }); + + git-lfs1 = callPackage ../applications/version-management/git-lfs/1.nix { }; + + git-ftp = callPackage ../development/tools/git-ftp { }; + + git-series = callPackage ../development/tools/git-series { }; + + git-sizer = callPackage ../applications/version-management/git-sizer { }; + + git-up = callPackage ../applications/version-management/git-up { }; + + gitfs = callPackage ../tools/filesystems/gitfs { }; + + gitinspector = callPackage ../applications/version-management/gitinspector { }; + + gitkraken = callPackage ../applications/version-management/gitkraken { }; + + gitlab = callPackage ../applications/version-management/gitlab { }; + gitlab-ee = callPackage ../applications/version-management/gitlab { gitlabEnterprise = true; }; + + gitlab-runner = callPackage ../development/tools/continuous-integration/gitlab-runner { }; + + gitlab-shell = callPackage ../applications/version-management/gitlab/gitlab-shell { }; + + gitlab-workhorse = callPackage ../applications/version-management/gitlab/gitlab-workhorse { }; + + gitaly = callPackage ../applications/version-management/gitlab/gitaly { }; + + gitstats = callPackage ../applications/version-management/gitstats { }; + + gogs = callPackage ../applications/version-management/gogs { }; + + git-latexdiff = callPackage ../tools/typesetting/git-latexdiff { }; + + gitea = callPackage ../applications/version-management/gitea { }; + + gl2ps = callPackage ../development/libraries/gl2ps { }; + + glusterfs = callPackage ../tools/filesystems/glusterfs { }; + + glmark2 = callPackage ../tools/graphics/glmark2 { }; + + glogg = libsForQt5.callPackage ../tools/text/glogg { }; + + glxinfo = callPackage ../tools/graphics/glxinfo { }; + + gmrender-resurrect = callPackage ../tools/networking/gmrender-resurrect { + inherit (gst_all_1) gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav; + }; + + gmvault = callPackage ../tools/networking/gmvault { }; + + gnash = callPackage ../misc/gnash { }; + + gnaural = callPackage ../applications/audio/gnaural { + stdenv = gcc49Stdenv; + }; + + gnirehtet = callPackage ../tools/networking/gnirehtet { }; + + gnome15 = callPackage ../applications/misc/gnome15 { + inherit (gnome2) gnome_python gnome_python_desktop; + }; + + gnome-builder = callPackage ../applications/editors/gnome-builder { }; + + gnome-podcasts = callPackage ../applications/audio/gnome-podcasts { }; + + gnome-photos = callPackage ../applications/graphics/gnome-photos { + gegl = gnome3.gegl_0_4; + }; + + gnokii = callPackage ../tools/misc/gnokii { }; + + gnuapl = callPackage ../development/interpreters/gnu-apl { }; + + gnu-cobol = callPackage ../development/compilers/gnu-cobol { }; + + gnuclad = callPackage ../applications/graphics/gnuclad { }; + + gnufdisk = callPackage ../tools/system/fdisk { + guile = guile_1_8; + }; + + gnugrep = callPackage ../tools/text/gnugrep { }; + + gnulib = callPackage ../development/tools/gnulib { }; + + gnupatch = callPackage ../tools/text/gnupatch { }; + + gnupg1orig = callPackage ../tools/security/gnupg/1.nix { }; + gnupg1compat = callPackage ../tools/security/gnupg/1compat.nix { }; + gnupg1 = gnupg1compat; # use config.packageOverrides if you prefer original gnupg1 + gnupg20 = callPackage ../tools/security/gnupg/20.nix { + pinentry = if stdenv.isDarwin then pinentry_mac else pinentry; + }; + gnupg22 = callPackage ../tools/security/gnupg/22.nix { + pinentry = if stdenv.isDarwin then pinentry_mac else pinentry; + }; + gnupg = gnupg22; + + gnuplot = libsForQt5.callPackage ../tools/graphics/gnuplot { }; + + gnuplot_qt = gnuplot.override { withQt = true; }; + + # must have AquaTerm installed separately + gnuplot_aquaterm = gnuplot.override { aquaterm = true; }; + + gnu-pw-mgr = callPackage ../tools/security/gnu-pw-mgr { }; + + gnused = if !stdenv.hostPlatform.isWindows then + callPackage ../tools/text/gnused { } # broken on Windows + else + gnused_422; + # This is an easy work-around for [:space:] problems. + gnused_422 = callPackage ../tools/text/gnused/422.nix { }; + + gnutar = callPackage ../tools/archivers/gnutar { }; + + gnuvd = callPackage ../tools/misc/gnuvd { }; + + goaccess = callPackage ../tools/misc/goaccess { }; + + gocryptfs = callPackage ../tools/filesystems/gocryptfs { }; + + godot = callPackage ../development/tools/godot {}; + + goklp = callPackage ../tools/networking/goklp {}; + + go-mtpfs = callPackage ../tools/filesystems/go-mtpfs { }; + + go-sct = callPackage ../tools/X11/go-sct { }; + + # rename to upower-notify? + go-upower-notify = callPackage ../tools/misc/upower-notify { }; + + google-app-engine-go-sdk = callPackage ../development/tools/google-app-engine-go-sdk { }; + + google-authenticator = callPackage ../os-specific/linux/google-authenticator { }; + + google-cloud-sdk = python2.pkgs.google-cloud-sdk; + google-cloud-sdk-gce = python2.pkgs.google-cloud-sdk-gce; + + google-fonts = callPackage ../data/fonts/google-fonts { }; + + google-clasp = callPackage ../development/misc/google-clasp { }; + + google-compute-engine = python2.pkgs.google-compute-engine; + + google-compute-engine-oslogin = callPackage ../tools/virtualization/google-compute-engine-oslogin { }; + + google-music-scripts = callPackage ../tools/audio/google-music-scripts { }; + + google-cloud-cpp = callPackage ../development/libraries/google-cloud-cpp { }; + + gopro = callPackage ../tools/video/gopro { }; + + gource = callPackage ../applications/version-management/gource { }; + + govc = callPackage ../tools/virtualization/govc { }; + + gpart = callPackage ../tools/filesystems/gpart { }; + + gparted = callPackage ../tools/misc/gparted { }; + + ldmtool = callPackage ../tools/misc/ldmtool { }; + + gpodder = callPackage ../applications/audio/gpodder { }; + + gpp = callPackage ../development/tools/gpp { }; + + gpredict = callPackage ../applications/science/astronomy/gpredict { }; + + gptfdisk = callPackage ../tools/system/gptfdisk { }; + + grafx2 = callPackage ../applications/graphics/grafx2 {}; + + grails = callPackage ../development/web/grails { jdk = null; }; + + graylog = callPackage ../tools/misc/graylog { }; + graylogPlugins = recurseIntoAttrs ( + callPackage ../tools/misc/graylog/plugins.nix { } + ); + + graphviz = callPackage ../tools/graphics/graphviz { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + }; + + graphviz-nox = graphviz.override { + xorg = null; + libdevil = libdevil-nox; + }; + + /* Readded by Michael Raskin. There are programs in the wild + * that do want 2.32 but not 2.0 or 2.36. Please give a day's notice for + * objections before removal. The feature is libgraph. + */ + graphviz_2_32 = (callPackage ../tools/graphics/graphviz/2.32.nix { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + }).overrideAttrs(x: { configureFlags = x.configureFlags ++ ["--with-cgraph=no"];}); + + grin = callPackage ../tools/text/grin { }; + + ripgrep = callPackage ../tools/text/ripgrep { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + ripgrep-all = callPackage ../tools/text/ripgrep-all { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + grive2 = callPackage ../tools/filesystems/grive2 { }; + + groff = callPackage ../tools/text/groff { + ghostscript = null; + psutils = null; + netpbm = null; + }; + + gromit-mpx = callPackage ../tools/graphics/gromit-mpx { + gtk = gtk3; + libappindicator = libappindicator-gtk3; + inherit (xorg) libXdmcp; + }; + + gron = callPackage ../development/tools/gron { }; + + groonga = callPackage ../servers/search/groonga { }; + + grpcurl = callPackage ../tools/networking/grpcurl { }; + + grpcui = callPackage ../tools/networking/grpcui { }; + + grub = pkgsi686Linux.callPackage ../tools/misc/grub ({ + stdenv = overrideCC stdenv buildPackages.pkgsi686Linux.gcc6; + } // (config.grub or {})); + + trustedGrub = pkgsi686Linux.callPackage ../tools/misc/grub/trusted.nix { }; + + trustedGrub-for-HP = pkgsi686Linux.callPackage ../tools/misc/grub/trusted.nix { for_HP_laptop = true; }; + + grub2 = grub2_full; + + grub2_full = callPackage ../tools/misc/grub/2.0x.nix { }; + + grub2_efi = grub2.override { + efiSupport = true; + }; + + grub2_light = grub2.override { + zfsSupport = false; + }; + + grub2_xen = grub2_full.override { + xenSupport = true; + }; + + grub2_pvgrub_image = callPackage ../tools/misc/grub/pvgrub_image { }; + + grub4dos = callPackage ../tools/misc/grub4dos { + stdenv = stdenv_32bit; + }; + + gx = callPackage ../tools/package-management/gx { }; + gx-go = callPackage ../tools/package-management/gx/go { }; + + efitools = callPackage ../tools/security/efitools { }; + + sbsigntool = callPackage ../tools/security/sbsigntool { }; + + gsmartcontrol = callPackage ../tools/misc/gsmartcontrol { }; + + gssdp = callPackage ../development/libraries/gssdp { }; + + gt5 = callPackage ../tools/system/gt5 { }; + + gtest = callPackage ../development/libraries/gtest { }; + gmock = gtest; # TODO: move to aliases.nix + + gbenchmark = callPackage ../development/libraries/gbenchmark {}; + + gtkdatabox = callPackage ../development/libraries/gtkdatabox {}; + + gtklick = callPackage ../applications/audio/gtklick {}; + + gtdialog = callPackage ../development/libraries/gtdialog {}; + + gtkd = callPackage ../development/libraries/gtkd { }; + + gtkgnutella = callPackage ../tools/networking/p2p/gtk-gnutella { }; + + gtkperf = callPackage ../development/tools/misc/gtkperf { }; + + gtk-vnc = callPackage ../tools/admin/gtk-vnc {}; + + gtmess = callPackage ../applications/networking/instant-messengers/gtmess { + openssl = openssl_1_0_2; + }; + + gup = callPackage ../development/tools/build-managers/gup {}; + + gupnp = callPackage ../development/libraries/gupnp { }; + + gupnp-av = callPackage ../development/libraries/gupnp-av {}; + + gupnp-dlna = callPackage ../development/libraries/gupnp-dlna {}; + + gupnp-igd = callPackage ../development/libraries/gupnp-igd {}; + + gupnp-tools = callPackage ../tools/networking/gupnp-tools {}; + + gvpe = callPackage ../tools/networking/gvpe { + openssl = openssl_1_0_2; + }; + + gvolicon = callPackage ../tools/audio/gvolicon {}; + + gzip = callPackage ../tools/compression/gzip { }; + + gzrt = callPackage ../tools/compression/gzrt { }; + + httplab = callPackage ../tools/networking/httplab { }; + + partclone = callPackage ../tools/backup/partclone { }; + + partimage = callPackage ../tools/backup/partimage { }; + + pgf_graphics = callPackage ../tools/graphics/pgf { }; + + pgloader = callPackage ../development/tools/pgloader { }; + + pigz = callPackage ../tools/compression/pigz { }; + + pixz = callPackage ../tools/compression/pixz { }; + + pxattr = callPackage ../tools/archivers/pxattr { }; + + pxz = callPackage ../tools/compression/pxz { }; + + hans = callPackage ../tools/networking/hans { }; + + h2 = callPackage ../servers/h2 { }; + + h5utils = callPackage ../tools/misc/h5utils { + libmatheval = null; + hdf4 = null; + }; + + haproxy = callPackage ../tools/networking/haproxy { + stdenv = if stdenv.cc.isClang then llvmPackages_6.stdenv else stdenv; + }; + + hackertyper = callPackage ../tools/misc/hackertyper { }; + + haveged = callPackage ../tools/security/haveged { }; + + habitat = callPackage ../applications/networking/cluster/habitat { }; + + hardlink = callPackage ../tools/system/hardlink { }; + + hashcash = callPackage ../tools/security/hashcash { }; + + hashcat = callPackage ../tools/security/hashcat { }; + + hashcat-utils = callPackage ../tools/security/hashcat-utils { }; + + hash_extender = callPackage ../tools/security/hash_extender { }; + + hash-slinger = callPackage ../tools/security/hash-slinger { }; + + hal-flash = callPackage ../os-specific/linux/hal-flash { }; + + half = callPackage ../development/libraries/half { }; + + halibut = callPackage ../tools/typesetting/halibut { }; + + halide = callPackage ../development/compilers/halide { llvmPackages=llvmPackages_6; }; + + ham = pkgs.perlPackages.ham; + + hardinfo = callPackage ../tools/system/hardinfo { }; + + hcxtools = callPackage ../tools/security/hcxtools { }; + + hdapsd = callPackage ../os-specific/linux/hdapsd { }; + + hdaps-gl = callPackage ../tools/misc/hdaps-gl { }; + + hddtemp = callPackage ../tools/misc/hddtemp { }; + + hdf4 = callPackage ../tools/misc/hdf4 { + szip = null; + }; + + hdf5 = callPackage ../tools/misc/hdf5 { + gfortran = null; + szip = null; + mpi = null; + }; + + hdf5_1_8 = callPackage ../tools/misc/hdf5/1_8.nix { + gfortran = null; + szip = null; + mpi = null; + }; + + hdf5-mpi = appendToName "mpi" (hdf5.override { + szip = null; + mpi = pkgs.openmpi; + }); + + hdf5-cpp = appendToName "cpp" (hdf5.override { + cpp = true; + }); + + hdf5-fortran = appendToName "fortran" (hdf5.override { + inherit gfortran; + }); + + hdf5-threadsafe = appendToName "threadsafe" (hdf5.overrideAttrs (oldAttrs: { + # Threadsafe hdf5 + # However, hdf5 hl (High Level) library is not considered stable + # with thread safety and should be disabled. + configureFlags = oldAttrs.configureFlags ++ ["--enable-threadsafe" "--disable-hl" ]; + })); + + hdfview = callPackage ../tools/misc/hdfview { + javac = jdk; + }; + + hdf_java = callPackage ../tools/misc/hdfjava { + javac = jdk; + }; + + hecate = callPackage ../applications/editors/hecate { }; + + heaptrack = libsForQt5.callPackage ../development/tools/profiling/heaptrack {}; + + heimdall = libsForQt5.callPackage ../tools/misc/heimdall { }; + + heimdall-gui = heimdall.override { enableGUI = true; }; + + helio-workstation = callPackage ../applications/audio/helio-workstation { }; + + hevea = callPackage ../tools/typesetting/hevea { }; + + hexd = callPackage ../tools/misc/hexd { }; + pixd = callPackage ../tools/misc/pixd { }; + + hhpc = callPackage ../tools/misc/hhpc { }; + + hiera-eyaml = callPackage ../tools/system/hiera-eyaml { }; + + hivemind = callPackage ../applications/misc/hivemind { }; + + hfsprogs = callPackage ../tools/filesystems/hfsprogs { }; + + highlight = callPackage ../tools/text/highlight ({ + lua = lua5; + } // lib.optionalAttrs stdenv.isDarwin { + inherit (llvmPackages_38) stdenv; + }); + + holochain-go = callPackage ../servers/holochain-go { }; + + homesick = callPackage ../tools/misc/homesick { }; + + honcho = callPackage ../tools/system/honcho { }; + + horst = callPackage ../tools/networking/horst { }; + + host = bind.host; + + hotpatch = callPackage ../development/libraries/hotpatch { }; + + hotspot = libsForQt5.callPackage ../development/tools/analysis/hotspot { }; + + hping = callPackage ../tools/networking/hping { }; + + html-proofer = callPackage ../tools/misc/html-proofer { }; + + htpdate = callPackage ../tools/networking/htpdate { }; + + http-prompt = callPackage ../tools/networking/http-prompt { }; + + http-getter = callPackage ../applications/networking/flent/http-getter.nix { }; + + httpie = callPackage ../tools/networking/httpie { }; + + httping = callPackage ../tools/networking/httping {}; + + httplz = callPackage ../tools/networking/httplz { }; + + httpfs2 = callPackage ../tools/filesystems/httpfs { }; + + httpstat = callPackage ../tools/networking/httpstat { }; + + httptunnel = callPackage ../tools/networking/httptunnel { }; + + hubicfuse = callPackage ../tools/filesystems/hubicfuse { }; + + humanfriendly = with python3Packages; toPythonApplication humanfriendly; + + hwinfo = callPackage ../tools/system/hwinfo { }; + + hybridreverb2 = callPackage ../applications/audio/hybridreverb2 { }; + + hylafaxplus = callPackage ../servers/hylafaxplus { }; + + i2c-tools = callPackage ../os-specific/linux/i2c-tools { }; + + i2p = callPackage ../tools/networking/i2p {}; + + i2pd = callPackage ../tools/networking/i2pd { + boost = boost165; + }; + + i-score = libsForQt5.callPackage ../applications/audio/i-score { }; + + iasl = callPackage ../development/compilers/iasl { }; + + iannix = libsForQt5.callPackage ../applications/audio/iannix { }; + + ibm-sw-tpm2 = callPackage ../tools/security/ibm-sw-tpm2 { }; + + ibniz = callPackage ../tools/graphics/ibniz { }; + + icecast = callPackage ../servers/icecast { }; + + iceshelf = callPackage ../tools/backup/iceshelf { }; + + darkice = callPackage ../tools/audio/darkice { }; + + deco = callPackage ../applications/misc/deco { }; + + icoutils = callPackage ../tools/graphics/icoutils { }; + + idutils = callPackage ../tools/misc/idutils { }; + + idle3tools = callPackage ../tools/system/idle3tools { }; + + iftop = callPackage ../tools/networking/iftop { }; + + ifuse = callPackage ../tools/filesystems/ifuse { }; + ideviceinstaller = callPackage ../tools/misc/ideviceinstaller { }; + idevicerestore = callPackage ../tools/misc/idevicerestore { }; + + inherit (callPackages ../tools/filesystems/irods rec { + stdenv = llvmPackages_38.libcxxStdenv; + libcxx = llvmPackages_38.libcxx; + boost = boost160.override { inherit stdenv; }; + avro-cpp_llvm = avro-cpp.override { inherit stdenv boost; }; + }) + irods + irods-icommands; + + ignition = recurseIntoAttrs { + + math = callPackage ../development/libraries/ignition-math { }; + + math2 = ignition.math; + + transport0 = callPackage ../development/libraries/ignition-transport/0.9.0.nix { }; + + transport1 = callPackage ../development/libraries/ignition-transport/1.0.1.nix { }; + + transport = ignition.transport0; + }; + + + ihaskell = callPackage ../development/tools/haskell/ihaskell/wrapper.nix { + inherit (haskellPackages) ghcWithPackages; + + jupyter = python3.withPackages (ps: [ ps.jupyter ps.notebook ]); + + packages = config.ihaskell.packages or (self: []); + }; + + imapproxy = callPackage ../tools/networking/imapproxy { + openssl = openssl_1_0_2; + }; + + imapsync = callPackage ../tools/networking/imapsync { }; + + imgur-screenshot = callPackage ../tools/graphics/imgur-screenshot { }; + + imgurbash2 = callPackage ../tools/graphics/imgurbash2 { }; + + inadyn = callPackage ../tools/networking/inadyn { }; + + inboxer = callPackage ../applications/networking/mailreaders/inboxer { }; + + incron = callPackage ../tools/system/incron { }; + + inetutils = callPackage ../tools/networking/inetutils { }; + + inform7 = callPackage ../development/compilers/inform7 { }; + + infamousPlugins = callPackage ../applications/audio/infamousPlugins { }; + + innoextract = callPackage ../tools/archivers/innoextract { }; + + input-utils = callPackage ../os-specific/linux/input-utils { }; + + intecture-agent = callPackage ../tools/admin/intecture/agent.nix { }; + + intecture-auth = callPackage ../tools/admin/intecture/auth.nix { }; + + intecture-cli = callPackage ../tools/admin/intecture/cli.nix { }; + + intel-media-sdk = callPackage ../development/libraries/intel-media-sdk { }; + + invoice2data = callPackage ../tools/text/invoice2data { }; + + inxi = callPackage ../tools/system/inxi { }; + + iodine = callPackage ../tools/networking/iodine { }; + + ioping = callPackage ../tools/system/ioping { }; + + iops = callPackage ../tools/system/iops { }; + + ior = callPackage ../tools/system/ior { }; + + iouyap = callPackage ../tools/networking/iouyap { }; + + ip2location = callPackage ../tools/networking/ip2location { }; + + ip2unix = callPackage ../tools/networking/ip2unix { }; + + ipad_charge = callPackage ../tools/misc/ipad_charge { }; + + iperf2 = callPackage ../tools/networking/iperf/2.nix { }; + iperf3 = callPackage ../tools/networking/iperf/3.nix { }; + iperf = iperf3; + + ipfs = callPackage ../applications/networking/ipfs { }; + ipfs-migrator = callPackage ../applications/networking/ipfs-migrator { }; + ipfs-cluster = callPackage ../applications/networking/ipfs-cluster { }; + + ipget = callPackage ../applications/networking/ipget { + buildGoPackage = buildGo110Package; + }; + + ipmitool = callPackage ../tools/system/ipmitool { + openssl = openssl_1_0_2; + }; + + ipmiutil = callPackage ../tools/system/ipmiutil {}; + + ipmicfg = callPackage ../applications/misc/ipmicfg {}; + + ipmiview = callPackage ../applications/misc/ipmiview {}; + + ipcalc = callPackage ../tools/networking/ipcalc {}; + + netmask = callPackage ../tools/networking/netmask {}; + + ipv6calc = callPackage ../tools/networking/ipv6calc {}; + + ipxe = callPackage ../tools/misc/ipxe { }; + + irker = callPackage ../servers/irker { }; + + ised = callPackage ../tools/misc/ised {}; + + isl = isl_0_20; + isl_0_11 = callPackage ../development/libraries/isl/0.11.1.nix { }; + isl_0_14 = callPackage ../development/libraries/isl/0.14.1.nix { }; + isl_0_17 = callPackage ../development/libraries/isl/0.17.1.nix { }; + isl_0_20 = callPackage ../development/libraries/isl/0.20.0.nix { }; + + ispike = callPackage ../development/libraries/science/robotics/ispike { }; + + isync = callPackage ../tools/networking/isync { }; + + jaaa = callPackage ../applications/audio/jaaa { }; + + jackett = callPackage ../servers/jackett { }; + + jade = callPackage ../tools/text/sgml/jade { }; + + jazzy = callPackage ../development/tools/jazzy { }; + + jd = callPackage ../development/tools/jd { }; + + jd-gui = callPackage ../tools/security/jd-gui { }; + + jdiskreport = callPackage ../tools/misc/jdiskreport { }; + + jekyll = callPackage ../applications/misc/jekyll { }; + + jfsutils = callPackage ../tools/filesystems/jfsutils { }; + + jhead = callPackage ../tools/graphics/jhead { }; + + jid = callPackage ../development/tools/jid { }; + + jing = res.jing-trang; + jing-trang = callPackage ../tools/text/xml/jing-trang { }; + + jira-cli = callPackage ../development/tools/jira_cli { }; + + jitterentropy = callPackage ../development/libraries/jitterentropy { }; + + jl = haskellPackages.callPackage ../development/tools/jl { }; + + jmespath = callPackage ../development/tools/jmespath { }; + + jmtpfs = callPackage ../tools/filesystems/jmtpfs { }; + + jnettop = callPackage ../tools/networking/jnettop { }; + + junkie = callPackage ../tools/networking/junkie { }; + + just = callPackage ../development/tools/just { }; + + go-jira = callPackage ../applications/misc/go-jira { }; + + john = callPackage ../tools/security/john { }; + + joplin = nodePackages.joplin; + + joplin-desktop = callPackage ../applications/misc/joplin-desktop { }; + + journaldriver = callPackage ../tools/misc/journaldriver { }; + + jp = callPackage ../development/tools/jp { }; + + jp2a = callPackage ../applications/misc/jp2a { }; + + jpeg-archive = callPackage ../applications/graphics/jpeg-archive { }; + + jpeginfo = callPackage ../applications/graphics/jpeginfo { }; + + jpegoptim = callPackage ../applications/graphics/jpegoptim { }; + + jpegrescan = callPackage ../applications/graphics/jpegrescan { }; + + jpylyzer = with pythonPackages; toPythonApplication jpylyzer; + + jq = callPackage ../development/tools/jq { }; + + jo = callPackage ../development/tools/jo { }; + + jrnl = callPackage ../applications/misc/jrnl { }; + + jsawk = callPackage ../tools/text/jsawk { }; + + jscoverage = callPackage ../development/tools/misc/jscoverage { }; + + jsduck = callPackage ../development/tools/jsduck { }; + + jumpapp = callPackage ../tools/X11/jumpapp {}; + + jucipp = callPackage ../applications/editors/jucipp { }; + + jupp = callPackage ../applications/editors/jupp { }; + + jupyter = callPackage ../applications/editors/jupyter { }; + + jupyter-kernel = callPackage ../applications/editors/jupyter/kernel.nix { }; + + jwhois = callPackage ../tools/networking/jwhois { }; + + k2pdfopt = callPackage ../applications/misc/k2pdfopt { }; + + kargo = callPackage ../tools/misc/kargo { }; + + kazam = callPackage ../applications/video/kazam { }; + + kalibrate-rtl = callPackage ../applications/radio/kalibrate-rtl { }; + + kalibrate-hackrf = callPackage ../applications/radio/kalibrate-hackrf { }; + + wrapKakoune = callPackage ../applications/editors/kakoune/wrapper.nix { }; + kakounePlugins = callPackage ../applications/editors/kakoune/plugins.nix { }; + kakoune-unwrapped = callPackage ../applications/editors/kakoune { }; + kakoune = wrapKakoune kakoune-unwrapped { }; + + kak-lsp = callPackage ../tools/misc/kak-lsp { }; + + kbdd = callPackage ../applications/window-managers/kbdd { }; + + kdbplus = pkgsi686Linux.callPackage ../applications/misc/kdbplus { }; + + kde2-decoration = libsForQt5.callPackage ../misc/themes/kde2 { }; + + keepalived = callPackage ../tools/networking/keepalived { }; + + kexectools = callPackage ../os-specific/linux/kexectools { }; + + kexpand = callPackage ../development/tools/kexpand { }; + + keybase = callPackage ../tools/security/keybase { + # Reasoning for the inherited apple_sdk.frameworks: + # 1. specific compiler errors about: AVFoundation, AudioToolbox, MediaToolbox + # 2. the rest are added from here: https://github.com/keybase/client/blob/68bb8c893c5214040d86ea36f2f86fbb7fac8d39/go/chat/attachments/preview_darwin.go#L7 + # #cgo LDFLAGS: -framework AVFoundation -framework CoreFoundation -framework ImageIO -framework CoreMedia -framework Foundation -framework CoreGraphics -lobjc + # with the exception of CoreFoundation, due to the warning in https://github.com/NixOS/nixpkgs/blob/master/pkgs/os-specific/darwin/apple-sdk/frameworks.nix#L25 + inherit (darwin.apple_sdk.frameworks) AVFoundation AudioToolbox ImageIO CoreMedia Foundation CoreGraphics MediaToolbox; + }; + + kbfs = callPackage ../tools/security/keybase/kbfs.nix { }; + + keybase-gui = callPackage ../tools/security/keybase/gui.nix { }; + + keychain = callPackage ../tools/misc/keychain { }; + + keyfuzz = callPackage ../tools/inputmethods/keyfuzz { }; + + kibana5 = callPackage ../development/tools/misc/kibana/5.x.nix { }; + kibana6 = callPackage ../development/tools/misc/kibana/6.x.nix { }; + kibana6-oss = callPackage ../development/tools/misc/kibana/6.x.nix { + enableUnfree = false; + }; + kibana7 = callPackage ../development/tools/misc/kibana/7.x.nix { }; + kibana7-oss = callPackage ../development/tools/misc/kibana/7.x.nix { + enableUnfree = false; + }; + kibana = kibana6; + kibana-oss = kibana6-oss; + + kismet = callPackage ../applications/networking/sniffers/kismet { }; + + klick = callPackage ../applications/audio/klick { }; + + klystrack = callPackage ../applications/audio/klystrack { }; + + knockknock = callPackage ../tools/security/knockknock { }; + + kore = callPackage ../development/web/kore { }; + + krakenx = callPackage ../tools/system/krakenx { }; + + partition-manager = libsForQt5.callPackage ../tools/misc/partition-manager { }; + + kpcli = callPackage ../tools/security/kpcli { }; + + krename = libsForQt5.callPackage ../applications/misc/krename { }; + + krunner-pass = libsForQt5.callPackage ../tools/security/krunner-pass { }; + + kronometer = libsForQt5.callPackage ../tools/misc/kronometer { }; + + krop = callPackage ../applications/graphics/krop { }; + + elisa = libsForQt5.callPackage ../applications/audio/elisa { }; + + kdiff3 = libsForQt5.callPackage ../tools/text/kdiff3 { }; + + kube-router = callPackage ../applications/networking/cluster/kube-router { }; + + kwalletcli = libsForQt5.callPackage ../tools/security/kwalletcli { }; + + peruse = libsForQt5.callPackage ../tools/misc/peruse { }; + + kst = libsForQt5.callPackage ../tools/graphics/kst { gsl = gsl_1; }; + + kytea = callPackage ../tools/text/kytea { }; + + k6 = callPackage ../development/tools/k6 { }; + + lalezar-fonts = callPackage ../data/fonts/lalezar-fonts { }; + + ldc = callPackage ../development/compilers/ldc { }; + + lbreakout2 = callPackage ../games/lbreakout2 { }; + + lego = callPackage ../tools/admin/lego { }; + + leocad = callPackage ../applications/graphics/leocad { }; + + less = callPackage ../tools/misc/less { }; + + lf = callPackage ../tools/misc/lf {}; + + lhasa = callPackage ../tools/compression/lhasa {}; + + libcpuid = callPackage ../tools/misc/libcpuid { }; + + libcsptr = callPackage ../development/libraries/libcsptr { }; + + libscrypt = callPackage ../development/libraries/libscrypt { }; + + libcloudproviders = callPackage ../development/libraries/libcloudproviders { }; + + libcoap = callPackage ../applications/networking/libcoap {}; + + libcroco = callPackage ../development/libraries/libcroco { }; + + libcryptui = callPackage ../development/libraries/libcryptui { }; + + libsmi = callPackage ../development/libraries/libsmi { }; + + lesspipe = callPackage ../tools/misc/lesspipe { }; + + liquidsoap = callPackage ../tools/audio/liquidsoap/full.nix { + ffmpeg = ffmpeg-full; + }; + + lksctp-tools = callPackage ../os-specific/linux/lksctp-tools { }; + + lldpd = callPackage ../tools/networking/lldpd { }; + + lnav = callPackage ../tools/misc/lnav { }; + + loadlibrary = callPackage ../tools/misc/loadlibrary { }; + + loc = callPackage ../development/misc/loc { }; + + lockfileProgs = callPackage ../tools/misc/lockfile-progs { }; + + logstash5 = callPackage ../tools/misc/logstash/5.x.nix { }; + logstash6 = callPackage ../tools/misc/logstash/6.x.nix { }; + logstash6-oss = callPackage ../tools/misc/logstash/6.x.nix { + enableUnfree = false; + }; + logstash7 = callPackage ../tools/misc/logstash/7.x.nix { }; + logstash7-oss = callPackage ../tools/misc/logstash/7.x.nix { + enableUnfree = false; + }; + logstash = logstash6; + + logstash-contrib = callPackage ../tools/misc/logstash/contrib.nix { }; + + lolcat = callPackage ../tools/misc/lolcat { }; + + lsd = callPackage ../tools/misc/lsd { }; + + lsdvd = callPackage ../tools/cd-dvd/lsdvd {}; + + lsyncd = callPackage ../applications/networking/sync/lsyncd { + lua = lua5_2_compat; + }; + + ltwheelconf = callPackage ../applications/misc/ltwheelconf { }; + + lvmsync = callPackage ../tools/backup/lvmsync { }; + + kdbg = libsForQt5.callPackage ../development/tools/misc/kdbg { }; + + kippo = callPackage ../servers/kippo { }; + + kzipmix = pkgsi686Linux.callPackage ../tools/compression/kzipmix { }; + + mailcatcher = callPackage ../development/web/mailcatcher { }; + + makebootfat = callPackage ../tools/misc/makebootfat { }; + + matrix-synapse = callPackage ../servers/matrix-synapse { }; + + mautrix-telegram = recurseIntoAttrs (callPackage ../servers/mautrix-telegram { }); + + mautrix-whatsapp = callPackage ../servers/mautrix-whatsapp { }; + + mcfly = callPackage ../tools/misc/mcfly { }; + + mdbook = callPackage ../tools/text/mdbook { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + medfile = callPackage ../development/libraries/medfile { }; + + memtester = callPackage ../tools/system/memtester { }; + + minergate = callPackage ../applications/misc/minergate { }; + + minergate-cli = callPackage ../applications/misc/minergate-cli { }; + + minidlna = callPackage ../tools/networking/minidlna { }; + + minisign = callPackage ../tools/security/minisign { }; + + ministat = callPackage ../tools/misc/ministat { }; + + mmv = callPackage ../tools/misc/mmv { }; + + most = callPackage ../tools/misc/most { }; + + motion = callPackage ../applications/video/motion { }; + + mtail = callPackage ../servers/monitoring/mtail { }; + + multitail = callPackage ../tools/misc/multitail { }; + + mxt-app = callPackage ../misc/mxt-app { }; + + mxisd = callPackage ../servers/mxisd { }; + + nagstamon = callPackage ../tools/misc/nagstamon { + pythonPackages = python3Packages; + }; + + nbench = callPackage ../tools/misc/nbench { }; + + netdata = callPackage ../tools/system/netdata { + inherit (darwin.apple_sdk.frameworks) CoreFoundation IOKit; + }; + + netsurf = recurseIntoAttrs (let callPackage = newScope pkgs.netsurf; in rec { + # ui could be gtk, sixel or framebuffer. Note that console display (sixel) + # requires a terminal that supports `sixel` capabilities such as mlterm + # or xterm -ti 340 + ui = "sixel"; + + uilib = if ui == "gtk" then "gtk" else "framebuffer"; + + SDL = if ui == "gtk" then null else if ui == "sixel" then SDL_sixel else SDL; + + buildsystem = callPackage ../applications/misc/netsurf/buildsystem { }; + + libwapcaplet = callPackage ../applications/misc/netsurf/libwapcaplet { }; + + nsgenbind = callPackage ../applications/misc/netsurf/nsgenbind { }; + + libparserutils = callPackage ../applications/misc/netsurf/libparserutils { }; + + libnslog = callPackage ../applications/misc/netsurf/libnslog { }; + + libcss = callPackage ../applications/misc/netsurf/libcss { }; + + libhubbub = callPackage ../applications/misc/netsurf/libhubbub { }; + + libdom = callPackage ../applications/misc/netsurf/libdom { }; + + libnsbmp = callPackage ../applications/misc/netsurf/libnsbmp { }; + + libnsgif = callPackage ../applications/misc/netsurf/libnsgif { }; + + libnsfb = callPackage ../applications/misc/netsurf/libnsfb { }; + + libnsutils = callPackage ../applications/misc/netsurf/libnsutils { }; + + libsvgtiny = callPackage ../applications/misc/netsurf/libsvgtiny { }; + + libnspsl = callPackage ../applications/misc/netsurf/libnspsl { }; + + libutf8proc = callPackage ../applications/misc/netsurf/libutf8proc { }; + + browser = callPackage ../applications/misc/netsurf/browser { }; + + }); + + netperf = callPackage ../applications/networking/netperf { }; + + netsniff-ng = callPackage ../tools/networking/netsniff-ng { }; + + nfpm = callPackage ../tools/package-management/nfpm { }; + + nginx-config-formatter = callPackage ../tools/misc/nginx-config-formatter { }; + + ninka = callPackage ../development/tools/misc/ninka { }; + + nixnote2 = libsForQt5.callPackage ../applications/misc/nixnote2 { }; + + nodejs = hiPrio nodejs-10_x; + + nodejs-slim = nodejs-slim-10_x; + + + nodejs-10_x = callPackage ../development/web/nodejs/v10.nix { }; + nodejs-slim-10_x = callPackage ../development/web/nodejs/v10.nix { + enableNpm = false; + }; + nodejs-11_x = callPackage ../development/web/nodejs/v11.nix { }; + nodejs-slim-11_x = callPackage ../development/web/nodejs/v11.nix { + enableNpm = false; + }; + nodejs-12_x = callPackage ../development/web/nodejs/v12.nix { }; + nodejs-slim-12_x = callPackage ../development/web/nodejs/v12.nix { + enableNpm = false; + }; + + # Update this when adding the newest nodejs major version! + nodejs_latest = nodejs-12_x; + nodejs-slim_latest = nodejs-slim-12_x; + + nodePackages_12_x = dontRecurseIntoAttrs (callPackage ../development/node-packages/default-v12.nix { + nodejs = pkgs.nodejs-12_x; + }); + + nodePackages_10_x = dontRecurseIntoAttrs (callPackage ../development/node-packages/default-v10.nix { + nodejs = pkgs.nodejs-10_x; + }); + + nodePackages = nodePackages_10_x; + + now-cli = callPackage ../development/web/now-cli {}; + + file-rename = callPackage ../tools/filesystems/file-rename { }; + + kea = callPackage ../tools/networking/kea { + boost = boost165; + }; + + ispell = callPackage ../tools/text/ispell {}; + + jumanpp = callPackage ../tools/text/jumanpp {}; + + jump = callPackage ../tools/system/jump {}; + + kindlegen = callPackage ../tools/typesetting/kindlegen { }; + + latex2html = callPackage ../tools/misc/latex2html { }; + + latexrun = callPackage ../tools/typesetting/tex/latexrun { }; + + ldapvi = callPackage ../tools/misc/ldapvi { }; + + ldns = callPackage ../development/libraries/ldns { }; + + leafpad = callPackage ../applications/editors/leafpad { }; + + leatherman = callPackage ../development/libraries/leatherman { }; + + ledger-live-desktop = callPackage ../applications/altcoins/ledger-live-desktop { }; + + ledmon = callPackage ../tools/system/ledmon { }; + + leela = callPackage ../tools/graphics/leela { }; + + lftp = callPackage ../tools/networking/lftp { }; + + libconfig = callPackage ../development/libraries/libconfig { }; + + libcmis = callPackage ../development/libraries/libcmis { }; + + libee = callPackage ../development/libraries/libee { }; + + libepc = callPackage ../development/libraries/libepc { }; + + libestr = callPackage ../development/libraries/libestr { }; + + libevdev = callPackage ../development/libraries/libevdev { }; + + libfann = callPackage ../development/libraries/libfann { }; + + libfsm = callPackage ../development/libraries/libfsm { }; + + libgaminggear = callPackage ../development/libraries/libgaminggear { }; + + libhandy = callPackage ../development/libraries/libhandy { }; + + libgumath = callPackage ../development/libraries/libgumath { }; + + libipfix = callPackage ../development/libraries/libipfix { }; + + libircclient = callPackage ../development/libraries/libircclient { }; + + libite = callPackage ../development/libraries/libite { }; + + liblangtag = callPackage ../development/libraries/liblangtag { + inherit (gnome3) gnome-common; + }; + + liblouis = callPackage ../development/libraries/liblouis { }; + + liboauth = callPackage ../development/libraries/liboauth { }; + + libr3 = callPackage ../development/libraries/libr3 { }; + + libsidplayfp = callPackage ../development/libraries/libsidplayfp { }; + + libspf2 = callPackage ../development/libraries/libspf2 { }; + + libsrs2 = callPackage ../development/libraries/libsrs2 { }; + + libtermkey = callPackage ../development/libraries/libtermkey { }; + + libtelnet = callPackage ../development/libraries/libtelnet { }; + + libtirpc = callPackage ../development/libraries/ti-rpc { }; + + libtins = callPackage ../development/libraries/libtins { }; + + libshout = callPackage ../development/libraries/libshout { }; + + libqb = callPackage ../development/libraries/libqb { }; + + libqmi = callPackage ../development/libraries/libqmi { }; + + libmbim = callPackage ../development/libraries/libmbim { }; + + libmongo-client = callPackage ../development/libraries/libmongo-client { }; + + libmesode = callPackage ../development/libraries/libmesode {}; + + libnabo = callPackage ../development/libraries/libnabo { }; + + libngspice = callPackage ../development/libraries/libngspice { }; + + libpointmatcher = callPackage ../development/libraries/libpointmatcher { }; + + libmicrodns = callPackage ../development/libraries/libmicrodns { }; + + libnids = callPackage ../tools/networking/libnids { }; + + libtorrent = callPackage ../tools/networking/p2p/libtorrent { }; + + libmpack = callPackage ../development/libraries/libmpack { }; + + libiberty = callPackage ../development/libraries/libiberty { }; + + libxc = callPackage ../development/libraries/libxc { }; + + libxcomp = callPackage ../development/libraries/libxcomp { }; + + libxl = callPackage ../development/libraries/libxl {}; + + libx86emu = callPackage ../development/libraries/libx86emu { }; + + libzmf = callPackage ../development/libraries/libzmf {}; + + libreswan = callPackage ../tools/networking/libreswan { }; + + librest = callPackage ../development/libraries/librest { }; + + libwebsockets = callPackage ../development/libraries/libwebsockets { }; + + lidarr = callPackage ../servers/lidarr { }; + + limesuite = callPackage ../applications/radio/limesuite { }; + + limesurvey = callPackage ../servers/limesurvey { }; + + linuxquota = callPackage ../tools/misc/linuxquota { }; + + localtime = callPackage ../tools/system/localtime { }; + + logcheck = callPackage ../tools/system/logcheck { }; + + logmein-hamachi = callPackage ../tools/networking/logmein-hamachi { }; + + logkeys = callPackage ../tools/security/logkeys { }; + + logrotate = callPackage ../tools/system/logrotate { }; + + logstalgia = callPackage ../tools/graphics/logstalgia {}; + + loki = callPackage ../development/libraries/loki { }; + + longview = callPackage ../servers/monitoring/longview { }; + + lout = callPackage ../tools/typesetting/lout { }; + + lr = callPackage ../tools/system/lr { }; + + lrzip = callPackage ../tools/compression/lrzip { }; + + lsb-release = callPackage ../os-specific/linux/lsb-release { }; + + # lsh installs `bin/nettle-lfib-stream' and so does Nettle. Give the + # former a lower priority than Nettle. + lsh = lowPrio (callPackage ../tools/networking/lsh { }); + + lshw = callPackage ../tools/system/lshw { }; + + ltris = callPackage ../games/ltris { }; + + lxc = callPackage ../os-specific/linux/lxc { }; + lxcfs = callPackage ../os-specific/linux/lxcfs { }; + lxd = callPackage ../tools/admin/lxd { }; + + lzfse = callPackage ../tools/compression/lzfse { }; + + lzham = callPackage ../tools/compression/lzham { }; + + lzip = callPackage ../tools/compression/lzip { }; + + luxcorerender = callPackage ../tools/graphics/luxcorerender { }; + + xz = callPackage ../tools/compression/xz { }; + lzma = xz; # TODO: move to aliases.nix + + lz4 = callPackage ../tools/compression/lz4 { }; + + lzbench = callPackage ../tools/compression/lzbench { }; + + lzop = callPackage ../tools/compression/lzop { }; + + macchanger = callPackage ../os-specific/linux/macchanger { }; + + madlang = haskell.lib.justStaticExecutables haskellPackages.madlang; + + mailcheck = callPackage ../applications/networking/mailreaders/mailcheck { }; + + maildrop = callPackage ../tools/networking/maildrop { }; + + mailhog = callPackage ../servers/mail/mailhog {}; + + mailnag = callPackage ../applications/networking/mailreaders/mailnag { + pythonPackages = python2Packages; + }; + + mailsend = callPackage ../tools/networking/mailsend { }; + + mailpile = callPackage ../applications/networking/mailreaders/mailpile { }; + + mailutils = callPackage ../tools/networking/mailutils { + guile = guile_2_0; # compilation fails with guile 2.2 + sasl = gsasl; + }; + + email = callPackage ../tools/networking/email { }; + + maim = callPackage ../tools/graphics/maim {}; + + mairix = callPackage ../tools/text/mairix { }; + + makemkv = libsForQt5.callPackage ../applications/video/makemkv { }; + + makerpm = callPackage ../development/tools/makerpm { }; + + makefile2graph = callPackage ../development/tools/analysis/makefile2graph { }; + + # See https://github.com/NixOS/nixpkgs/issues/15849. I'm switching on isLinux because + # it looks like gnulib is broken on non-linux, so it seems likely that this would cause + # trouble on bsd and/or cygwin as well. + man = if stdenv.isLinux then man-db else man-old; + + man-old = callPackage ../tools/misc/man { }; + + man-db = callPackage ../tools/misc/man-db { }; + + mandoc = callPackage ../tools/misc/mandoc { }; + + mawk = callPackage ../tools/text/mawk { }; + + mb2md = callPackage ../tools/text/mb2md { }; + + mbox = callPackage ../tools/security/mbox { }; + + mbuffer = callPackage ../tools/misc/mbuffer { }; + + mdsh = callPackage ../development/tools/documentation/mdsh { }; + + mecab = + let + mecab-nodic = callPackage ../tools/text/mecab/nodic.nix { }; + in + callPackage ../tools/text/mecab { + mecab-ipadic = callPackage ../tools/text/mecab/ipadic.nix { + inherit mecab-nodic; + }; + }; + + mediawiki = callPackage ../servers/web-apps/mediawiki { }; + + memtier-benchmark = callPackage ../tools/networking/memtier-benchmark { }; + + memtest86-efi = callPackage ../tools/misc/memtest86-efi { }; + + memtest86plus = callPackage ../tools/misc/memtest86+ { }; + + meo = callPackage ../tools/security/meo { + boost = boost155; + }; + + mc = callPackage ../tools/misc/mc { }; + + mcabber = callPackage ../applications/networking/instant-messengers/mcabber { }; + + mcron = callPackage ../tools/system/mcron { + guile = guile_1_8; + }; + + mdbtools = callPackage ../tools/misc/mdbtools { }; + + mdk = callPackage ../development/tools/mdk { }; + + mdp = callPackage ../applications/misc/mdp { }; + + mednafen = callPackage ../misc/emulators/mednafen { }; + + mednafen-server = callPackage ../misc/emulators/mednafen/server.nix { }; + + mednaffe = callPackage ../misc/emulators/mednaffe { + gtk2 = null; + }; + + megacli = callPackage ../tools/misc/megacli { }; + + megatools = callPackage ../tools/networking/megatools { }; + + memo = callPackage ../applications/misc/memo { }; + + mencal = callPackage ../applications/misc/mencal { } ; + + metamorphose2 = callPackage ../applications/misc/metamorphose2 { }; + + metar = callPackage ../applications/misc/metar { }; + + mfcuk = callPackage ../tools/security/mfcuk { }; + + mfoc = callPackage ../tools/security/mfoc { }; + + mgba = libsForQt5.callPackage ../misc/emulators/mgba { }; + + midisheetmusic = callPackage ../applications/audio/midisheetmusic { }; + + mikutter = callPackage ../applications/networking/instant-messengers/mikutter { }; + + mimeo = callPackage ../tools/misc/mimeo { }; + + mimetic = callPackage ../development/libraries/mimetic { }; + + minetime = callPackage ../applications/office/minetime { }; + + minio-client = callPackage ../tools/networking/minio-client { + buildGoPackage = buildGo110Package; + }; + + minissdpd = callPackage ../tools/networking/minissdpd { }; + + inherit (callPackage ../tools/networking/miniupnpc + { inherit (darwin) cctools; }) + miniupnpc_1 miniupnpc_2; + miniupnpc = miniupnpc_1; + + miniupnpd = callPackage ../tools/networking/miniupnpd { }; + + miniball = callPackage ../development/libraries/miniball { }; + + minijail = callPackage ../tools/system/minijail { }; + + minixml = callPackage ../development/libraries/minixml { }; + + mir-qualia = callPackage ../tools/text/mir-qualia { + pythonPackages = python3Packages; + }; + + miredo = callPackage ../tools/networking/miredo { }; + + mirrorbits = callPackage ../servers/mirrorbits { + # XXX: this is failing with Go 1.12. Error is related to cgo, an + # update to this package might fix it. + buildGoPackage = buildGo111Package; + }; + + mitmproxy = callPackage ../tools/networking/mitmproxy { }; + + mjpegtools = callPackage ../tools/video/mjpegtools { }; + + mjpegtoolsFull = mjpegtools.override { + withMinimal = false; + }; + + mkclean = callPackage ../applications/video/mkclean {}; + + mkcue = callPackage ../tools/cd-dvd/mkcue { }; + + mkp224o = callPackage ../tools/security/mkp224o { }; + + mkpasswd = hiPrio (callPackage ../tools/security/mkpasswd { }); + + mkrand = callPackage ../tools/security/mkrand { }; + + mktemp = callPackage ../tools/security/mktemp { }; + + mktorrent = callPackage ../tools/misc/mktorrent { }; + + mmake = callPackage ../tools/misc/mmake { }; + + modemmanager = callPackage ../tools/networking/modem-manager {}; + + modem-manager-gui = callPackage ../applications/networking/modem-manager-gui {}; + + modsecurity_standalone = callPackage ../tools/security/modsecurity { }; + + molly-guard = callPackage ../os-specific/linux/molly-guard { }; + + moneyplex = callPackage ../applications/office/moneyplex { }; + + monit = callPackage ../tools/system/monit { }; + + moreutils = callPackage ../tools/misc/moreutils { + docbook-xsl = docbook_xsl; + }; + + mosh = callPackage ../tools/networking/mosh { }; + + mpage = callPackage ../tools/text/mpage { }; + + mprime = callPackage ../tools/misc/mprime { }; + + mpw = callPackage ../tools/security/mpw { }; + + mr = callPackage ../applications/version-management/mr { }; + + mrtg = callPackage ../tools/misc/mrtg { }; + + mscgen = callPackage ../tools/graphics/mscgen { }; + + metasploit = callPackage ../tools/security/metasploit { }; + + ms-sys = callPackage ../tools/misc/ms-sys { }; + + mtdutils = callPackage ../tools/filesystems/mtdutils { }; + + mtools = callPackage ../tools/filesystems/mtools { }; + + mtr = callPackage ../tools/networking/mtr {}; + + mtx = callPackage ../tools/backup/mtx {}; + + mt-st = callPackage ../tools/backup/mt-st {}; + + multitran = recurseIntoAttrs (let callPackage = newScope pkgs.multitran; in rec { + multitrandata = callPackage ../tools/text/multitran/data { }; + + libbtree = callPackage ../tools/text/multitran/libbtree { }; + + libmtsupport = callPackage ../tools/text/multitran/libmtsupport { }; + + libfacet = callPackage ../tools/text/multitran/libfacet { }; + + libmtquery = callPackage ../tools/text/multitran/libmtquery { }; + + mtutils = callPackage ../tools/text/multitran/mtutils { }; + }); + + munge = callPackage ../tools/security/munge { }; + + munt = libsForQt5.callPackage ../applications/audio/munt { }; + + mycli = callPackage ../tools/admin/mycli { }; + + mydumper = callPackage ../tools/backup/mydumper { }; + + mysql2pgsql = callPackage ../tools/misc/mysql2pgsql { }; + + mysqltuner = callPackage ../tools/misc/mysqltuner { }; + + mytetra = libsForQt5.callPackage ../applications/office/mytetra { }; + + nabi = callPackage ../tools/inputmethods/nabi { }; + + nahid-fonts = callPackage ../data/fonts/nahid-fonts { }; + + namazu = callPackage ../tools/text/namazu { }; + + nano-wallet = libsForQt5.callPackage ../applications/altcoins/nano-wallet { }; + + nasty = callPackage ../tools/security/nasty { }; + + nat-traverse = callPackage ../tools/networking/nat-traverse { }; + + nawk = callPackage ../tools/text/nawk { }; + + nbd = callPackage ../tools/networking/nbd { }; + xnbd = callPackage ../tools/networking/xnbd { }; + + nccl = callPackage ../development/libraries/science/math/nccl { }; + nccl_cudatoolkit_9_0 = nccl.override { cudatoolkit = cudatoolkit_9_0; }; + nccl_cudatoolkit_9 = nccl.override { cudatoolkit = cudatoolkit_9; }; + nccl_cudatoolkit_10 = nccl.override { cudatoolkit = cudatoolkit_10; }; + + ndjbdns = callPackage ../tools/networking/ndjbdns { }; + + ndppd = callPackage ../applications/networking/ndppd { }; + + neofetch = callPackage ../tools/misc/neofetch { }; + + nerdfonts = callPackage ../data/fonts/nerdfonts { }; + + nestopia = callPackage ../misc/emulators/nestopia { }; + + netatalk = callPackage ../tools/filesystems/netatalk { }; + + netcdf = callPackage ../development/libraries/netcdf { }; + + netcdf-mpi = appendToName "mpi" (netcdf.override { + hdf5 = hdf5-mpi; + }); + + netcdfcxx4 = callPackage ../development/libraries/netcdf-cxx4 { }; + + netcdffortran = callPackage ../development/libraries/netcdf-fortran { }; + + neural-style = callPackage ../tools/graphics/neural-style {}; + + nco = callPackage ../development/libraries/nco { }; + + ncftp = callPackage ../tools/networking/ncftp { }; + + ncompress = callPackage ../tools/compression/ncompress { }; + + ndisc6 = callPackage ../tools/networking/ndisc6 { }; + + neopg = callPackage ../tools/security/neopg { }; + + netboot = callPackage ../tools/networking/netboot {}; + + netcat = libressl.nc; + + netcat-gnu = callPackage ../tools/networking/netcat { }; + + nethogs = callPackage ../tools/networking/nethogs { }; + + netkittftp = callPackage ../tools/networking/netkit/tftp { }; + + netpbm = callPackage ../tools/graphics/netpbm { }; + + netrw = callPackage ../tools/networking/netrw { }; + + netselect = callPackage ../tools/networking/netselect { }; + + nettee = callPackage ../tools/networking/nettee { + inherit (skawarePackages) cleanPackaging; + }; + + # stripped down, needed by steam + networkmanager098 = callPackage ../tools/networking/network-manager/0.9.8 { }; + + networkmanager = callPackage ../tools/networking/network-manager { }; + + networkmanager-iodine = callPackage ../tools/networking/network-manager/iodine { }; + + networkmanager-openvpn = callPackage ../tools/networking/network-manager/openvpn { }; + + networkmanager-l2tp = callPackage ../tools/networking/network-manager/l2tp { }; + + networkmanager-vpnc = callPackage ../tools/networking/network-manager/vpnc { }; + + networkmanager-openconnect = callPackage ../tools/networking/network-manager/openconnect { }; + + networkmanager-fortisslvpn = callPackage ../tools/networking/network-manager/fortisslvpn { }; + + networkmanager_strongswan = callPackage ../tools/networking/network-manager/strongswan.nix { }; + + networkmanagerapplet = callPackage ../tools/networking/network-manager/applet.nix { }; + + networkmanager_dmenu = callPackage ../tools/networking/network-manager/dmenu.nix { }; + + newsboat = callPackage ../applications/networking/feedreaders/newsboat { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + nextcloud = callPackage ../servers/nextcloud { }; + + nextcloud-client = libsForQt5.callPackage ../applications/networking/nextcloud-client { }; + + nextcloud-news-updater = callPackage ../servers/nextcloud/news-updater.nix { }; + + ndstool = callPackage ../tools/archivers/ndstool { }; + + ngrep = callPackage ../tools/networking/ngrep { }; + + ngrok = ngrok-2; + + ngrok-2 = callPackage ../tools/networking/ngrok-2 { }; + + ngrok-1 = callPackage ../tools/networking/ngrok-1 { }; + + noice = callPackage ../applications/misc/noice { }; + + noip = callPackage ../tools/networking/noip { }; + + nomad = callPackage ../applications/networking/cluster/nomad { }; + + notable = callPackage ../applications/misc/notable { }; + + miller = callPackage ../tools/text/miller { }; + + milu = callPackage ../applications/misc/milu { }; + + mpack = callPackage ../tools/networking/mpack { }; + + mtm = callPackage ../tools/misc/mtm { }; + + pa_applet = callPackage ../tools/audio/pa-applet { }; + + pandoc-imagine = python3Packages.callPackage ../tools/misc/pandoc-imagine { }; + + pasystray = callPackage ../tools/audio/pasystray { }; + + phash = callPackage ../development/libraries/phash { }; + + pnmixer = callPackage ../tools/audio/pnmixer { }; + + pro-office-calculator = libsForQt5.callPackage ../games/pro-office-calculator { }; + + pulsemixer = callPackage ../tools/audio/pulsemixer { }; + + pwsafe = callPackage ../applications/misc/pwsafe { }; + + niff = callPackage ../tools/package-management/niff { }; + + nifskope = libsForQt59.callPackage ../tools/graphics/nifskope { }; + + nilfs-utils = callPackage ../tools/filesystems/nilfs-utils {}; + + nitrogen = callPackage ../tools/X11/nitrogen {}; + + nms = callPackage ../tools/misc/nms { }; + + nomachine-client = callPackage ../tools/admin/nomachine-client { }; + + notify-desktop = callPackage ../tools/misc/notify-desktop {}; + + nkf = callPackage ../tools/text/nkf {}; + + nlopt = callPackage ../development/libraries/nlopt { octave = null; }; + + npapi_sdk = callPackage ../development/libraries/npapi-sdk {}; + + npth = callPackage ../development/libraries/npth {}; + + nmap = callPackage ../tools/security/nmap { }; + + nmap-graphical = nmap.override { + graphicalSupport = true; + }; + + nmapsi4 = libsForQt5.callPackage ../tools/security/nmap/qt.nix { }; + + nnn = callPackage ../applications/misc/nnn { }; + + notary = callPackage ../tools/security/notary { + buildGoPackage = buildGo110Package; + }; + + notify-osd = callPackage ../applications/misc/notify-osd { }; + + notes-up = callPackage ../applications/office/notes-up { }; + + notify-osd-customizable = callPackage ../applications/misc/notify-osd-customizable { }; + + nox = callPackage ../tools/package-management/nox { }; + + nq = callPackage ../tools/system/nq { }; + + nsjail = callPackage ../tools/security/nsjail {}; + + nss_pam_ldapd = callPackage ../tools/networking/nss-pam-ldapd {}; + + ntfs3g = callPackage ../tools/filesystems/ntfs-3g { }; + + # ntfsprogs are merged into ntfs-3g + ntfsprogs = pkgs.ntfs3g; + + ntfy = callPackage ../tools/misc/ntfy {}; + + ntopng = callPackage ../tools/networking/ntopng { }; + + ntp = callPackage ../tools/networking/ntp { + libcap = if stdenv.isLinux then libcap else null; + }; + + numdiff = callPackage ../tools/text/numdiff { }; + + numlockx = callPackage ../tools/X11/numlockx { }; + + nuttcp = callPackage ../tools/networking/nuttcp { }; + + nssmdns = callPackage ../tools/networking/nss-mdns { }; + + nwdiag = with python3Packages; toPythonApplication nwdiag; + + nyancat = callPackage ../tools/misc/nyancat { }; + + nylon = callPackage ../tools/networking/nylon { }; + + nzbget = callPackage ../tools/networking/nzbget { }; + + oathToolkit = callPackage ../tools/security/oath-toolkit { }; + + obex_data_server = callPackage ../tools/bluetooth/obex-data-server { }; + + obexd = callPackage ../tools/bluetooth/obexd { }; + + obfs4 = callPackage ../tools/networking/obfs4 { }; + + oci-image-tool = callPackage ../tools/misc/oci-image-tool { }; + + ocproxy = callPackage ../tools/networking/ocproxy { }; + + ocserv = callPackage ../tools/networking/ocserv { }; + + openfortivpn = callPackage ../tools/networking/openfortivpn { }; + + obexfs = callPackage ../tools/bluetooth/obexfs { }; + + obexftp = callPackage ../tools/bluetooth/obexftp { }; + + objconv = callPackage ../development/tools/misc/objconv {}; + + odpdown = callPackage ../tools/typesetting/odpdown { }; + + odpic = callPackage ../development/libraries/odpic { }; + + odt2txt = callPackage ../tools/text/odt2txt { }; + + odyssey = callPackage ../tools/misc/odyssey { }; + + offlineimap = callPackage ../tools/networking/offlineimap { }; + + ofono-phonesim = libsForQt5.callPackage ../development/tools/ofono-phonesim/default.nix { }; + + oh-my-zsh = callPackage ../shells/zsh/oh-my-zsh { }; + + ola = callPackage ../applications/misc/ola { }; + + olive-editor = libsForQt5.callPackage ../applications/video/olive-editor { + inherit (darwin.apple_sdk.frameworks) CoreFoundation; + }; + + omping = callPackage ../applications/networking/omping { }; + + onioncircuits = callPackage ../tools/security/onioncircuits { }; + + openapi-generator-cli = callPackage ../tools/networking/openapi-generator-cli { }; + + opencc = callPackage ../tools/text/opencc { }; + + opencl-info = callPackage ../tools/system/opencl-info { }; + + opencryptoki = callPackage ../tools/security/opencryptoki { }; + + opendbx = callPackage ../development/libraries/opendbx { }; + + opendht = callPackage ../development/libraries/opendht {}; + + opendkim = callPackage ../development/libraries/opendkim { }; + + opendylan = callPackage ../development/compilers/opendylan { + opendylan-bootstrap = opendylan_bin; + }; + + opendylan_bin = callPackage ../development/compilers/opendylan/bin.nix { }; + + open-ecard = callPackage ../tools/security/open-ecard { }; + + openjade = callPackage ../tools/text/sgml/openjade { }; + + openmvg = callPackage ../applications/science/misc/openmvg { }; + + openmvs = callPackage ../applications/science/misc/openmvs { }; + + openntpd = callPackage ../tools/networking/openntpd { }; + + openntpd_nixos = openntpd.override { + privsepUser = "ntp"; + privsepPath = "/var/empty"; + }; + + openobex = callPackage ../tools/bluetooth/openobex { }; + + openresolv = callPackage ../tools/networking/openresolv { }; + + opensc = callPackage ../tools/security/opensc { + inherit (darwin.apple_sdk.frameworks) Carbon PCSC; + }; + + opensm = callPackage ../tools/networking/opensm { }; + + openssh = + callPackage ../tools/networking/openssh { + hpnSupport = false; + etcDir = "/etc/ssh"; + pam = if stdenv.isLinux then pam else null; + }; + + openssh_hpn = pkgs.appendToName "with-hpn" (openssh.override { + hpnSupport = true; + # the hpn patchset does not yet support openssl>1.0.2 + # https://github.com/rapier1/openssh-portable/issues/14 + openssl = openssl_1_0_2; + }); + + openssh_gssapi = pkgs.appendToName "with-gssapi" (openssh.override { + withGssapiPatches = true; + }); + + opensp = callPackage ../tools/text/sgml/opensp { }; + + opentracker = callPackage ../applications/networking/p2p/opentracker { }; + + opentsdb = callPackage ../tools/misc/opentsdb {}; + + openvpn = callPackage ../tools/networking/openvpn {}; + + openvpn_learnaddress = callPackage ../tools/networking/openvpn/openvpn_learnaddress.nix { }; + + openvpn-auth-ldap = callPackage ../tools/networking/openvpn/openvpn-auth-ldap.nix { + stdenv = clangStdenv; + }; + + oppai-ng = callPackage ../tools/misc/oppai-ng { }; + + update-dotdee = with python3Packages; toPythonApplication update-dotdee; + + update-resolv-conf = callPackage ../tools/networking/openvpn/update-resolv-conf.nix { }; + + opae = callPackage ../development/libraries/opae { }; + + opentracing-cpp = callPackage ../development/libraries/opentracing-cpp { }; + + openvswitch = callPackage ../os-specific/linux/openvswitch { + openssl = openssl_1_0_2; + }; + + optipng = callPackage ../tools/graphics/optipng { + libpng = libpng12; + }; + + olsrd = callPackage ../tools/networking/olsrd { }; + + opl3bankeditor = libsForQt5.callPackage ../tools/audio/opl3bankeditor { }; + + opn2bankeditor = callPackage ../tools/audio/opl3bankeditor/opn2bankeditor.nix { }; + + os-prober = callPackage ../tools/misc/os-prober {}; + + osl = callPackage ../development/compilers/osl { }; + + ossec = callPackage ../tools/security/ossec {}; + + osslsigncode = callPackage ../development/tools/osslsigncode {}; + + ostree = callPackage ../tools/misc/ostree { }; + + otfcc = callPackage ../tools/misc/otfcc { }; + + otpw = callPackage ../os-specific/linux/otpw { }; + + overmind = callPackage ../applications/misc/overmind { }; + + owncloud-client = libsForQt5.callPackage ../applications/networking/owncloud-client { }; + + oxidized = callPackage ../tools/admin/oxidized { }; + + oxipng = callPackage ../tools/graphics/oxipng { }; + + p2pvc = callPackage ../applications/video/p2pvc {}; + + p7zip = callPackage ../tools/archivers/p7zip { }; + + packagekit = callPackage ../tools/package-management/packagekit { }; + + packagekit-qt = libsForQt5.callPackage ../tools/package-management/packagekit/qt.nix { }; + + packetdrill = callPackage ../tools/networking/packetdrill { }; + + pacman = callPackage ../tools/package-management/pacman { }; + + padthv1 = libsForQt5.callPackage ../applications/audio/padthv1 { }; + + pagmo2 = callPackage ../development/libraries/pagmo2 { }; + + pakcs = callPackage ../development/compilers/pakcs { }; + + pal = callPackage ../tools/misc/pal { }; + + pandoc = haskell.lib.overrideCabal (haskell.lib.justStaticExecutables haskellPackages.pandoc) (drv: { + configureFlags = drv.configureFlags or [] ++ ["-fembed_data_files"]; + buildDepends = drv.buildDepends or [] ++ [haskellPackages.file-embed]; + }); + + pamtester = callPackage ../tools/security/pamtester { }; + + paper-gtk-theme = callPackage ../misc/themes/paper { }; + + paperless = callPackage ../applications/office/paperless { }; + + paperwork = callPackage ../applications/office/paperwork { }; + + papertrail = callPackage ../tools/text/papertrail { }; + + par2cmdline = callPackage ../tools/networking/par2cmdline { }; + + parallel = callPackage ../tools/misc/parallel { }; + + parastoo-fonts = callPackage ../data/fonts/parastoo-fonts { }; + + parcellite = callPackage ../tools/misc/parcellite { }; + + patchutils = callPackage ../tools/text/patchutils { }; + + patchutils_0_3_3 = callPackage ../tools/text/patchutils/0.3.3.nix { }; + + parted = callPackage ../tools/misc/parted { }; + + paulstretch = callPackage ../applications/audio/paulstretch { }; + + pazi = callPackage ../tools/misc/pazi { }; + + pell = callPackage ../applications/misc/pell { }; + + pepper = callPackage ../tools/admin/salt/pepper { }; + + perceptualdiff = callPackage ../tools/graphics/perceptualdiff { }; + + percona-xtrabackup = callPackage ../tools/backup/percona-xtrabackup { + boost = boost159; + }; + + pick = callPackage ../tools/misc/pick { }; + + pitivi = callPackage ../applications/video/pitivi { }; + + pulumi-bin = callPackage ../tools/admin/pulumi { }; + + p0f = callPackage ../tools/security/p0f { }; + + pngout = callPackage ../tools/graphics/pngout { }; + + ipsecTools = callPackage ../os-specific/linux/ipsec-tools { + flex = flex_2_5_35; + openssl = openssl_1_0_2; + }; + + patch = gnupatch; + + patchage = callPackage ../applications/audio/patchage { }; + + patchwork-classic = callPackage ../applications/networking/ssb/patchwork-classic { }; + + pcapfix = callPackage ../tools/networking/pcapfix { }; + + pbzip2 = callPackage ../tools/compression/pbzip2 { }; + + pciutils = callPackage ../tools/system/pciutils { }; + + pcsclite = callPackage ../tools/security/pcsclite { + inherit (darwin.apple_sdk.frameworks) IOKit; + }; + + pcsctools = callPackage ../tools/security/pcsctools { }; + + pcsc-cyberjack = callPackage ../tools/security/pcsc-cyberjack { }; + + pcsc-scm-scl011 = callPackage ../tools/security/pcsc-scm-scl011 { }; + ifdnfc = callPackage ../tools/security/ifdnfc { }; + + pdd = python3Packages.callPackage ../tools/misc/pdd { }; + + pdf2djvu = callPackage ../tools/typesetting/pdf2djvu { }; + + pdf2htmlEX = callPackage ../tools/typesetting/pdf2htmlEX { }; + + pdf2odt = callPackage ../tools/typesetting/pdf2odt { }; + + pdf-redact-tools = callPackage ../tools/graphics/pdfredacttools { }; + + pdfcrack = callPackage ../tools/security/pdfcrack { }; + + pdfsandwich = callPackage ../tools/typesetting/pdfsandwich { }; + + pdftag = callPackage ../tools/graphics/pdftag { }; + + pdf2svg = callPackage ../tools/graphics/pdf2svg { }; + + fmodex = callPackage ../games/zandronum/fmod.nix { }; + + pdfmod = callPackage ../applications/misc/pdfmod { }; + + pdf-quench = callPackage ../applications/misc/pdf-quench { }; + + jbig2enc = callPackage ../tools/graphics/jbig2enc { }; + + pdfread = callPackage ../tools/graphics/pdfread { + inherit (pythonPackages) pillow; + }; + + briss = callPackage ../tools/graphics/briss { }; + + brickd = callPackage ../servers/brickd { + libusb = libusb1; + }; + + bully = callPackage ../tools/networking/bully { + openssl = openssl_1_0_2; + }; + + pcapc = callPackage ../tools/networking/pcapc { }; + + pdnsd = callPackage ../tools/networking/pdnsd { }; + + peco = callPackage ../tools/text/peco { }; + + pg_top = callPackage ../tools/misc/pg_top { }; + + pgcenter = callPackage ../tools/misc/pgcenter { }; + + pgmetrics = callPackage ../tools/misc/pgmetrics { }; + + pdsh = callPackage ../tools/networking/pdsh { + rsh = true; # enable internal rsh implementation + ssh = openssh; + }; + + pfstools = callPackage ../tools/graphics/pfstools { }; + + philter = callPackage ../tools/networking/philter { }; + + phodav = callPackage ../tools/networking/phodav { }; + + pinentry = callPackage ../tools/security/pinentry { + libcap = if stdenv.isDarwin then null else libcap; + gcr = null; + qt4 = null; + qt5 = null; + }; + + pinentry_ncurses = res.pinentry.override { + gtk2 = null; + }; + + pinentry_emacs = res.pinentry.override { + enableEmacs = true; + }; + + pinentry_gnome = res.pinentry.override { + inherit gcr; + }; + + pinentry_qt4 = res.pinentry.override { + gtk2 = null; + inherit qt4; + }; + + pinentry_qt5 = res.pinentry.override { + gtk2 = null; + inherit qt5; + }; + + pinentry_mac = callPackage ../tools/security/pinentry/mac.nix { + inherit (darwin.apple_sdk.frameworks) Cocoa; + xcbuildHook = xcbuild6Hook; + }; + + pingtcp = callPackage ../tools/networking/pingtcp { }; + + pirate-get = callPackage ../tools/networking/pirate-get { }; + + pipreqs = callPackage ../tools/misc/pipreqs { }; + + pius = callPackage ../tools/security/pius { }; + + pixiewps = callPackage ../tools/networking/pixiewps {}; + + pk2cmd = callPackage ../tools/misc/pk2cmd { }; + + plantuml = callPackage ../tools/misc/plantuml { + # Graphviz 2.39 and 2.40 are discouraged by the PlantUML project, see + # http://plantuml.com/faq (heading: "Which version of Graphviz should I use ?") + graphviz = graphviz_2_32; + }; + + plan9port = callPackage ../tools/system/plan9port { }; + + platformioPackages = dontRecurseIntoAttrs (callPackage ../development/arduino/platformio { }); + platformio = platformioPackages.platformio-chrootenv; + + platinum-searcher = callPackage ../tools/text/platinum-searcher { }; + + playbar2 = libsForQt5.callPackage ../applications/audio/playbar2 { }; + + plex = callPackage ../servers/plex { }; + plexRaw = callPackage ../servers/plex/raw.nix { }; + + tautulli = callPackage ../servers/tautulli { python = python2; }; + + ploticus = callPackage ../tools/graphics/ploticus { + libpng = libpng12; + }; + + plotinus = callPackage ../tools/misc/plotinus { }; + + plotutils = callPackage ../tools/graphics/plotutils { }; + + plowshare = callPackage ../tools/misc/plowshare { }; + + pngcheck = callPackage ../tools/graphics/pngcheck { + zlib = zlib.override { + static = true; + }; + }; + + pngcrush = callPackage ../tools/graphics/pngcrush { }; + + pngnq = callPackage ../tools/graphics/pngnq { }; + + pngtoico = callPackage ../tools/graphics/pngtoico { + libpng = libpng12; + }; + + pngpp = callPackage ../development/libraries/png++ { }; + + pngquant = callPackage ../tools/graphics/pngquant { }; + + podiff = callPackage ../tools/text/podiff { }; + + podman = callPackage ../applications/virtualization/podman { }; + + pod2mdoc = callPackage ../tools/misc/pod2mdoc { }; + + poedit = callPackage ../tools/text/poedit { }; + + polipo = callPackage ../servers/polipo { }; + + polkit_gnome = callPackage ../tools/security/polkit-gnome { }; + + polysh = callPackage ../tools/networking/polysh { }; + + ponysay = callPackage ../tools/misc/ponysay { }; + + popfile = callPackage ../tools/text/popfile { }; + + poretools = callPackage ../applications/science/biology/poretools { }; + + postscript-lexmark = callPackage ../misc/drivers/postscript-lexmark { }; + + povray = callPackage ../tools/graphics/povray { }; + + ppl = callPackage ../development/libraries/ppl { }; + + ppp = callPackage ../tools/networking/ppp { }; + + pptp = callPackage ../tools/networking/pptp {}; + + pptpd = callPackage ../tools/networking/pptpd {}; + + pre-commit = gitAndTools.pre-commit; + + prettyping = callPackage ../tools/networking/prettyping { }; + + prey-bash-client = callPackage ../tools/security/prey { }; + + profile-cleaner = callPackage ../tools/misc/profile-cleaner { }; + + profile-sync-daemon = callPackage ../tools/misc/profile-sync-daemon { }; + + projectlibre = callPackage ../applications/misc/projectlibre { }; + + projectm = callPackage ../applications/audio/projectm { }; + + proot = callPackage ../tools/system/proot { }; + + prototypejs = callPackage ../development/libraries/prototypejs { }; + + proxmark3 = callPackage ../tools/security/proxmark3 { }; + + proxychains = callPackage ../tools/networking/proxychains { }; + + proxytunnel = callPackage ../tools/misc/proxytunnel { + openssl = openssl_1_0_2; + }; + + pws = callPackage ../tools/misc/pws { }; + + cntlm = callPackage ../tools/networking/cntlm { }; + + pastebinit = callPackage ../tools/misc/pastebinit { }; + + polygraph = callPackage ../tools/networking/polygraph { }; + + progress = callPackage ../tools/misc/progress { }; + + ps3netsrv = callPackage ../servers/ps3netsrv { }; + + pscircle = callPackage ../os-specific/linux/pscircle { }; + + psmisc = callPackage ../os-specific/linux/psmisc { }; + + pssh = callPackage ../tools/networking/pssh { }; + + pspg = callPackage ../tools/misc/pspg { }; + + pstoedit = callPackage ../tools/graphics/pstoedit { }; + + psutils = callPackage ../tools/typesetting/psutils { }; + + psensor = callPackage ../tools/system/psensor { + libXNVCtrl = linuxPackages.nvidia_x11.settings.libXNVCtrl; + }; + + pubs = callPackage ../tools/misc/pubs {}; + + pv = callPackage ../tools/misc/pv { }; + + pwgen = callPackage ../tools/security/pwgen { }; + + pwgen-secure = callPackage ../tools/security/pwgen-secure { }; + + pwnat = callPackage ../tools/networking/pwnat { }; + + pwndbg = python3Packages.callPackage ../development/tools/misc/pwndbg { }; + + pycangjie = pythonPackages.pycangjie; + + pydb = callPackage ../development/tools/pydb { }; + + pydf = callPackage ../applications/misc/pydf { }; + + pygmentex = callPackage ../tools/typesetting/pygmentex { }; + + pythonIRClib = pythonPackages.pythonIRClib; + + pythonSexy = pythonPackages.libsexy; + + pyditz = callPackage ../applications/misc/pyditz { + pythonPackages = python27Packages; + }; + + pytrainer = callPackage ../applications/misc/pytrainer { }; + + pywal = with python3Packages; toPythonApplication pywal; + + remarshal = callPackage ../development/tools/remarshal { }; + + rig = callPackage ../tools/misc/rig { + stdenv = gccStdenv; + }; + + rocket = libsForQt5.callPackage ../tools/graphics/rocket { }; + + rtaudio = callPackage ../development/libraries/audio/rtaudio { }; + + rtmidi = callPackage ../development/libraries/audio/rtmidi { }; + + openmpi = callPackage ../development/libraries/openmpi { }; + + openmodelica = callPackage ../applications/science/misc/openmodelica { }; + + qarte = callPackage ../applications/video/qarte { }; + + qlcplus = libsForQt5.callPackage ../applications/misc/qlcplus { }; + + qnial = callPackage ../development/interpreters/qnial { }; + + ocz-ssd-guru = callPackage ../tools/misc/ocz-ssd-guru { }; + + qalculate-gtk = callPackage ../applications/science/math/qalculate-gtk { }; + + qastools = libsForQt5.callPackage ../tools/audio/qastools { }; + + qesteidutil = libsForQt5.callPackage ../tools/security/qesteidutil { } ; + qdigidoc = libsForQt5.callPackage ../tools/security/qdigidoc { } ; + + qgrep = callPackage ../tools/text/qgrep {}; + + qhull = callPackage ../development/libraries/qhull { }; + + qjoypad = callPackage ../tools/misc/qjoypad { }; + + qownnotes = libsForQt5.callPackage ../applications/office/qownnotes { }; + + qpdf = callPackage ../development/libraries/qpdf { }; + + qprint = callPackage ../tools/text/qprint { }; + + qscintilla = callPackage ../development/libraries/qscintilla { }; + + qshowdiff = callPackage ../tools/text/qshowdiff { }; + + qr-filetransfer = callPackage ../tools/networking/qr-filetransfer { }; + + qtikz = libsForQt5.callPackage ../applications/graphics/ktikz { }; + + quickserve = callPackage ../tools/networking/quickserve { }; + + quicktun = callPackage ../tools/networking/quicktun { }; + + quilt = callPackage ../development/tools/quilt { }; + + quota = if stdenv.isLinux then linuxquota else unixtools.quota; + + qview = libsForQt5.callPackage ../applications/graphics/qview {}; + + wiggle = callPackage ../development/tools/wiggle { }; + + radamsa = callPackage ../tools/security/radamsa { }; + + radarr = callPackage ../servers/radarr { }; + + radeon-profile = libsForQt5.callPackage ../tools/misc/radeon-profile { }; + + radsecproxy = callPackage ../tools/networking/radsecproxy { }; + + radvd = callPackage ../tools/networking/radvd { }; + + rainbowstream = pythonPackages.rainbowstream; + + rambox = callPackage ../applications/networking/instant-messengers/rambox { }; + + rambox-pro = callPackage ../applications/networking/instant-messengers/rambox/pro.nix { }; + + ranger = callPackage ../applications/misc/ranger { }; + + rarcrack = callPackage ../tools/security/rarcrack { }; + + rarian = callPackage ../development/libraries/rarian { }; + + ratools = callPackage ../tools/networking/ratools { }; + + rawdog = callPackage ../applications/networking/feedreaders/rawdog { }; + + rc = callPackage ../shells/rc { }; + + rdma-core = callPackage ../os-specific/linux/rdma-core { }; + + react-native-debugger = callPackage ../development/tools/react-native-debugger { }; + + read-edid = callPackage ../os-specific/linux/read-edid { }; + + redir = callPackage ../tools/networking/redir { }; + + redmine = callPackage ../applications/version-management/redmine { ruby = pkgs.ruby_2_4; }; + # failed to build websocket-driver gem with ruby 2.6, so sticking to 2.5 for now + redmine_4 = callPackage ../applications/version-management/redmine/4.x { ruby = pkgs.ruby_2_5; }; + + redsocks = callPackage ../tools/networking/redsocks { }; + + retext = callPackage ../applications/editors/retext { }; + + richgo = callPackage ../development/tools/richgo { }; + + rst2html5 = callPackage ../tools/text/rst2html5 { }; + + rt = callPackage ../servers/rt { }; + + rtmpdump = callPackage ../tools/video/rtmpdump { + openssl = openssl_1_0_2; + }; + rtmpdump_gnutls = rtmpdump.override { gnutlsSupport = true; opensslSupport = false; }; + + reaverwps = callPackage ../tools/networking/reaver-wps {}; + + reaverwps-t6x = callPackage ../tools/networking/reaver-wps-t6x {}; + + recordmydesktop = callPackage ../applications/video/recordmydesktop { }; + + gtk-recordmydesktop = callPackage ../applications/video/recordmydesktop/gtk.nix { + jack2 = jack2Full; + }; + + qt-recordmydesktop = callPackage ../applications/video/recordmydesktop/qt.nix { + jack2 = jack2Full; + }; + + qt-box-editor = libsForQt5.callPackage ../applications/misc/qt-box-editor { }; + + recutils = callPackage ../tools/misc/recutils { }; + + recoll = callPackage ../applications/search/recoll { }; + + reflex = callPackage ../development/tools/reflex { }; + + reiser4progs = callPackage ../tools/filesystems/reiser4progs { }; + + reiserfsprogs = callPackage ../tools/filesystems/reiserfsprogs { }; + + relfs = callPackage ../tools/filesystems/relfs { + inherit (gnome2) gnome_vfs GConf; + }; + + remarkjs = callPackage ../development/web/remarkjs { }; + + alarm-clock-applet = callPackage ../tools/misc/alarm-clock-applet { }; + + remind = callPackage ../tools/misc/remind { }; + + remmina = callPackage ../applications/networking/remote/remmina { }; + + rename = callPackage ../tools/misc/rename { }; + + renameutils = callPackage ../tools/misc/renameutils { }; + + renderdoc = libsForQt5.callPackage ../applications/graphics/renderdoc { }; + + replace = callPackage ../tools/text/replace { }; + + reckon = callPackage ../tools/text/reckon { }; + + recoverjpeg = callPackage ../tools/misc/recoverjpeg { }; + + reftools = callPackage ../development/tools/reftools { }; + + reposurgeon = callPackage ../applications/version-management/reposurgeon { }; + + reptyr = callPackage ../os-specific/linux/reptyr {}; + + rescuetime = callPackage ../applications/misc/rescuetime { }; + + reuse = callPackage ../tools/package-management/reuse { }; + + rewritefs = callPackage ../os-specific/linux/rewritefs { }; + + rdiff-backup = callPackage ../tools/backup/rdiff-backup { }; + + rdfind = callPackage ../tools/filesystems/rdfind { }; + + rhash = callPackage ../tools/security/rhash { }; + + riemann_c_client = callPackage ../tools/misc/riemann-c-client { }; + riemann-tools = callPackage ../tools/misc/riemann-tools { }; + + ripmime = callPackage ../tools/networking/ripmime {}; + + rkflashtool = callPackage ../tools/misc/rkflashtool { }; + + rkrlv2 = callPackage ../applications/audio/rkrlv2 {}; + + rmlint = callPackage ../tools/misc/rmlint { + inherit (pythonPackages) sphinx; + }; + + rng-tools = callPackage ../tools/security/rng-tools { }; + + rnv = callPackage ../tools/text/xml/rnv { }; + + rounded-mgenplus = callPackage ../data/fonts/rounded-mgenplus { }; + + roundup = callPackage ../tools/misc/roundup { }; + + routino = callPackage ../tools/misc/routino { }; + + rq = callPackage ../development/tools/rq { }; + + rsnapshot = callPackage ../tools/backup/rsnapshot { }; + + rlwrap = callPackage ../tools/misc/rlwrap { }; + + rockbox_utility = libsForQt5.callPackage ../tools/misc/rockbox-utility { }; + + rosegarden = libsForQt5.callPackage ../applications/audio/rosegarden { }; + + rowhammer-test = callPackage ../tools/system/rowhammer-test { }; + + rpPPPoE = callPackage ../tools/networking/rp-pppoe { }; + + rpiboot-unstable = callPackage ../development/misc/rpiboot/unstable.nix { }; + + rpm = callPackage ../tools/package-management/rpm { }; + + rpm-ostree = callPackage ../tools/misc/rpm-ostree { + gperf = gperf_3_0; + }; + + rpmextract = callPackage ../tools/archivers/rpmextract { }; + + rrdtool = callPackage ../tools/misc/rrdtool { }; + + rsibreak = libsForQt5.callPackage ../applications/misc/rsibreak { }; + + rss2email = callPackage ../applications/networking/feedreaders/rss2email { + pythonPackages = python3Packages; + }; + + rsstail = callPackage ../applications/networking/feedreaders/rsstail { }; + + rtorrent = callPackage ../tools/networking/p2p/rtorrent { }; + + rubber = callPackage ../tools/typesetting/rubber { }; + + rubocop = callPackage ../development/tools/rubocop { }; + + runelite = callPackage ../games/runelite { }; + + runningx = callPackage ../tools/X11/runningx { }; + + runzip = callPackage ../tools/archivers/runzip { }; + + rw = callPackage ../tools/misc/rw { }; + + rxp = callPackage ../tools/text/xml/rxp { }; + + rzip = callPackage ../tools/compression/rzip { }; + + s-tui = callPackage ../tools/system/s-tui { }; + + s3backer = callPackage ../tools/filesystems/s3backer { }; + + s3fs = callPackage ../tools/filesystems/s3fs { }; + + s3cmd = callPackage ../tools/networking/s3cmd { }; + + s4cmd = callPackage ../tools/networking/s4cmd { }; + + s3gof3r = callPackage ../tools/networking/s3gof3r { }; + + s6-dns = skawarePackages.s6-dns; + + s6-linux-utils = skawarePackages.s6-linux-utils; + + s6-networking = skawarePackages.s6-networking; + + s6-portable-utils = skawarePackages.s6-portable-utils; + + sablotron = callPackage ../tools/text/xml/sablotron { }; + + safecopy = callPackage ../tools/system/safecopy { }; + + safe-rm = callPackage ../tools/system/safe-rm { }; + + safeeyes = callPackage ../applications/misc/safeeyes { }; + + sahel-fonts = callPackage ../data/fonts/sahel-fonts { }; + + salt = callPackage ../tools/admin/salt {}; + + salut_a_toi = callPackage ../applications/networking/instant-messengers/salut-a-toi {}; + + samim-fonts = callPackage ../data/fonts/samim-fonts {}; + + saml2aws = callPackage ../tools/security/saml2aws {}; + + samplicator = callPackage ../tools/networking/samplicator { }; + + sasview = callPackage ../applications/science/misc/sasview {}; + + scallion = callPackage ../tools/security/scallion { }; + + scanbd = callPackage ../tools/graphics/scanbd { }; + + scdoc = callPackage ../tools/typesetting/scdoc { }; + + scream-receivers = callPackage ../misc/scream-receivers { + pulseSupport = config.pulseaudio or false; + }; + + screen = callPackage ../tools/misc/screen { + inherit (darwin.apple_sdk.libs) utmp; + }; + + scrcpy = callPackage ../misc/scrcpy { + inherit (androidenv.androidPkgs_9_0) platform-tools; + }; + + screen-message = callPackage ../tools/X11/screen-message { }; + + screencloud = callPackage ../applications/graphics/screencloud { + quazip = quazip_qt4; + }; + + screenkey = python2Packages.callPackage ../applications/video/screenkey { }; + + quazip_qt4 = libsForQt5.quazip.override { + qtbase = qt4; + }; + + scfbuild = python2.pkgs.callPackage ../tools/misc/scfbuild { }; + + scriptaculous = callPackage ../development/libraries/scriptaculous { }; + + scrot = callPackage ../tools/graphics/scrot { }; + + scrypt = callPackage ../tools/security/scrypt { }; + + sd = callPackage ../tools/text/sd { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + sdate = callPackage ../tools/misc/sdate { }; + + sdcv = callPackage ../applications/misc/sdcv { }; + + sdl-jstest = callPackage ../tools/misc/sdl-jstest { }; + + skim = callPackage ../tools/misc/skim { }; + + sec = callPackage ../tools/admin/sec { }; + + seccure = callPackage ../tools/security/seccure { }; + + secp256k1 = callPackage ../tools/security/secp256k1 { }; + + securefs = callPackage ../tools/filesystems/securefs { }; + + seexpr = callPackage ../development/compilers/seexpr { }; + + setroot = callPackage ../tools/X11/setroot { }; + + setserial = callPackage ../tools/system/setserial { }; + + seqdiag = with python3Packages; toPythonApplication seqdiag; + + sequoia = callPackage ../tools/security/sequoia { + pythonPackages = python3Packages; + }; + + sewer = callPackage ../tools/admin/sewer { }; + + screenfetch = callPackage ../tools/misc/screenfetch { }; + + sg3_utils = callPackage ../tools/system/sg3_utils { }; + + sha1collisiondetection = callPackage ../tools/security/sha1collisiondetection { }; + + shadowsocks-libev = callPackage ../tools/networking/shadowsocks-libev { }; + + shabnam-fonts = callPackage ../data/fonts/shabnam-fonts { }; + + shadowsocks-rust = callPackage ../tools/networking/shadowsocks-rust { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + sharutils = callPackage ../tools/archivers/sharutils { }; + + shelldap = callPackage ../tools/misc/shelldap { }; + + schema2ldif = callPackage ../tools/text/schema2ldif { }; + + shocco = callPackage ../tools/text/shocco { }; + + shotwell = callPackage ../applications/graphics/shotwell { }; + + shout = nodePackages.shout; + + shellinabox = callPackage ../servers/shellinabox { + openssl = openssl_1_0_2; + }; + + shrikhand = callPackage ../data/fonts/shrikhand { }; + + sic = callPackage ../applications/networking/irc/sic { }; + + siege = callPackage ../tools/networking/siege {}; + + sieve-connect = callPackage ../applications/networking/sieve-connect {}; + + sigal = callPackage ../applications/misc/sigal { }; + + sigil = libsForQt5.callPackage ../applications/editors/sigil { }; + + signal-cli = callPackage ../applications/networking/instant-messengers/signal-cli { }; + + signal-desktop = callPackage ../applications/networking/instant-messengers/signal-desktop { }; + + slither-analyzer = with python3Packages; toPythonApplication slither-analyzer; + + signify = callPackage ../tools/security/signify { }; + + # aka., pgp-tools + signing-party = callPackage ../tools/security/signing-party { }; + + silc_client = callPackage ../applications/networking/instant-messengers/silc-client { }; + + silc_server = callPackage ../servers/silc-server { }; + + sile = callPackage ../tools/typesetting/sile { }; + + silver-searcher = callPackage ../tools/text/silver-searcher { }; + + simpleproxy = callPackage ../tools/networking/simpleproxy { }; + + simplescreenrecorder = libsForQt5.callPackage ../applications/video/simplescreenrecorder { }; + + sipsak = callPackage ../tools/networking/sipsak { }; + + sisco.lv2 = callPackage ../applications/audio/sisco.lv2 { }; + + sit = callPackage ../applications/version-management/sit { + inherit (darwin.apple_sdk.frameworks) CoreFoundation Security; + }; + + sixpair = callPackage ../tools/misc/sixpair {}; + + skippy-xd = callPackage ../tools/X11/skippy-xd {}; + + sks = callPackage ../servers/sks { inherit (ocaml-ng.ocamlPackages_4_02) ocaml camlp4; }; + + skydns = callPackage ../servers/skydns { }; + + sipcalc = callPackage ../tools/networking/sipcalc { }; + + skribilo = callPackage ../tools/typesetting/skribilo { + tex = texlive.combined.scheme-small; + }; + + sleuthkit = callPackage ../tools/system/sleuthkit {}; + + sleepyhead = callPackage ../applications/misc/sleepyhead {}; + + slimrat = callPackage ../tools/networking/slimrat { }; + + slirp4netns = callPackage ../tools/networking/slirp4netns/default.nix { }; + + slsnif = callPackage ../tools/misc/slsnif { }; + + slstatus = callPackage ../applications/misc/slstatus { + conf = config.slstatus.conf or null; + }; + + smartmontools = callPackage ../tools/system/smartmontools { + inherit (darwin.apple_sdk.frameworks) IOKit ApplicationServices; + }; + + smarty3 = callPackage ../development/libraries/smarty3 { }; + smarty3-i18n = callPackage ../development/libraries/smarty3-i18n { }; + + smbnetfs = callPackage ../tools/filesystems/smbnetfs {}; + + smenu = callPackage ../tools/misc/smenu { }; + + smesh = callPackage ../development/libraries/smesh {}; + + smugline = python3Packages.smugline; + + snabb = callPackage ../tools/networking/snabb { } ; + + snapcast = callPackage ../applications/audio/snapcast { }; + + sng = callPackage ../tools/graphics/sng { + libpng = libpng12; + }; + + snort = callPackage ../applications/networking/ids/snort { }; + + soapui = callPackage ../applications/networking/soapui { }; + + sshguard = callPackage ../tools/security/sshguard {}; + + suricata = callPackage ../applications/networking/ids/suricata { }; + + softhsm = callPackage ../tools/security/softhsm { + inherit (darwin) libobjc; + inherit (darwin.apple_sdk.frameworks) Security; + }; + + solr = solr_8; + solr_7 = callPackage ../servers/search/solr { }; + solr_8 = callPackage ../servers/search/solr/8.x.nix { }; + + solvespace = callPackage ../applications/graphics/solvespace { }; + + sonarr = callPackage ../servers/sonarr { }; + + sonata = callPackage ../applications/audio/sonata { }; + + soundkonverter = kdeApplications.callPackage ../applications/audio/soundkonverter {}; + + sparsehash = callPackage ../development/libraries/sparsehash { }; + + spectre-meltdown-checker = callPackage ../tools/security/spectre-meltdown-checker { }; + + spiped = callPackage ../tools/networking/spiped { }; + + sqliteman = callPackage ../applications/misc/sqliteman { }; + + stdman = callPackage ../data/documentation/stdman { }; + + stm32loader = with python3Packages; toPythonApplication stm32loader; + + storebrowse = callPackage ../tools/system/storebrowse { }; + + stubby = callPackage ../tools/networking/stubby { }; + + syntex = callPackage ../tools/graphics/syntex {}; + + fusesmb = callPackage ../tools/filesystems/fusesmb { samba = samba3; }; + + sl = callPackage ../tools/misc/sl { stdenv = gccStdenv; }; + + socat = callPackage ../tools/networking/socat { }; + + socat2pre = lowPrio (callPackage ../tools/networking/socat/2.x.nix { }); + + solaar = callPackage ../applications/misc/solaar {}; + + sourceHighlight = callPackage ../tools/text/source-highlight { }; + + spaceFM = callPackage ../applications/misc/spacefm { }; + + speech-denoiser = callPackage ../applications/audio/speech-denoiser {}; + + squashfsTools = callPackage ../tools/filesystems/squashfs { }; + + squashfuse = callPackage ../tools/filesystems/squashfuse { }; + + srcml = callPackage ../applications/version-management/srcml { }; + + sourcehut = callPackage ../applications/version-management/sourcehut { }; + + sshfs-fuse = callPackage ../tools/filesystems/sshfs-fuse { }; + sshfs = sshfs-fuse; # added 2017-08-14 + + sshlatex = callPackage ../tools/typesetting/sshlatex { }; + + sshuttle = callPackage ../tools/security/sshuttle { }; + + ssldump = callPackage ../tools/networking/ssldump { }; + + sstp = callPackage ../tools/networking/sstp {}; + + strip-nondeterminism = perlPackages.strip-nondeterminism; + + structure-synth = callPackage ../tools/graphics/structure-synth { }; + + su-exec = callPackage ../tools/security/su-exec {}; + + subberthehut = callPackage ../tools/misc/subberthehut { }; + + subsurface = libsForQt5.callPackage ../applications/misc/subsurface { }; + + sudo = callPackage ../tools/security/sudo { }; + + suidChroot = callPackage ../tools/system/suid-chroot { }; + + sundtek = callPackage ../misc/drivers/sundtek { }; + + sunxi-tools = callPackage ../development/tools/sunxi-tools { }; + + sumorobot-manager = python3Packages.callPackage ../applications/science/robotics/sumorobot-manager { }; + + super = callPackage ../tools/security/super { }; + + supertux-editor = callPackage ../applications/editors/supertux-editor { }; + + super-user-spark = haskellPackages.callPackage ../applications/misc/super_user_spark { }; + + svgbob = callPackage ../tools/graphics/svgbob { }; + + svgcleaner = callPackage ../tools/graphics/svgcleaner { }; + + ssdeep = callPackage ../tools/security/ssdeep { }; + + ssh-ident = callPackage ../tools/networking/ssh-ident { }; + + sshpass = callPackage ../tools/networking/sshpass { }; + + sslscan = callPackage ../tools/security/sslscan { + openssl = openssl_1_0_2.override { enableSSL2 = true; }; + }; + + sslmate = callPackage ../development/tools/sslmate { }; + + ssmtp = callPackage ../tools/networking/ssmtp { }; + + ssocr = callPackage ../applications/misc/ssocr { }; + + ssss = callPackage ../tools/security/ssss { }; + + stabber = callPackage ../misc/stabber { }; + + stress = callPackage ../tools/system/stress { }; + + stress-ng = callPackage ../tools/system/stress-ng { }; + + stoken = callPackage ../tools/security/stoken (config.stoken or {}); + + storeBackup = callPackage ../tools/backup/store-backup { }; + + stow = callPackage ../tools/misc/stow { }; + + stun = callPackage ../tools/networking/stun { }; + + stunnel = callPackage ../tools/networking/stunnel { }; + + stutter = haskell.lib.overrideCabal (haskell.lib.justStaticExecutables haskellPackages.stutter) (drv: { + preCheck = "export PATH=dist/build/stutter:$PATH"; + }); + + strongswan = callPackage ../tools/networking/strongswan { }; + strongswanTNC = strongswan.override { enableTNC = true; }; + strongswanNM = strongswan.override { enableNetworkManager = true; }; + + stylish-haskell = haskell.lib.justStaticExecutables haskellPackages.stylish-haskell; + + su = shadow.su; + + subsonic = callPackage ../servers/misc/subsonic { }; + + subfinder = callPackage ../tools/networking/subfinder { }; + + surfraw = callPackage ../tools/networking/surfraw { }; + + swagger-codegen = callPackage ../tools/networking/swagger-codegen { }; + + swec = callPackage ../tools/networking/swec { }; + + swfdec = callPackage ../tools/graphics/swfdec {}; + + svnfs = callPackage ../tools/filesystems/svnfs { }; + + svtplay-dl = callPackage ../tools/misc/svtplay-dl { }; + + symengine = callPackage ../development/libraries/symengine { }; + + sysbench = callPackage ../development/tools/misc/sysbench {}; + + system-config-printer = callPackage ../tools/misc/system-config-printer { + libxml2 = libxml2Python; + pythonPackages = python3Packages; + }; + + stricat = callPackage ../tools/security/stricat { }; + + staruml = callPackage ../tools/misc/staruml { inherit (gnome2) GConf; libgcrypt = libgcrypt_1_5; }; + + systrayhelper = callPackage ../tools/misc/systrayhelper {}; + + Sylk = callPackage ../applications/networking/Sylk {}; + + otter-browser = qt5.callPackage ../applications/networking/browsers/otter {}; + + privoxy = callPackage ../tools/networking/privoxy { + w3m = w3m-batch; + }; + + netalyzr = callPackage ../tools/networking/netalyzr { }; + + swaks = callPackage ../tools/networking/swaks { }; + + swiften = callPackage ../development/libraries/swiften { }; + + t = callPackage ../tools/misc/t { }; + + t1utils = callPackage ../tools/misc/t1utils { }; + + talkfilters = callPackage ../misc/talkfilters {}; + + znapzend = callPackage ../tools/backup/znapzend { }; + + targetcli = callPackage ../os-specific/linux/targetcli { }; + + tarsnap = callPackage ../tools/backup/tarsnap { }; + + tarsnapper = callPackage ../tools/backup/tarsnapper { }; + + tayga = callPackage ../tools/networking/tayga { }; + + tcpcrypt = callPackage ../tools/security/tcpcrypt { }; + + tcptraceroute = callPackage ../tools/networking/tcptraceroute { }; + + tboot = callPackage ../tools/security/tboot { }; + + tcpdump = callPackage ../tools/networking/tcpdump { }; + + tcpflow = callPackage ../tools/networking/tcpflow { + openssl = openssl_1_0_2; + }; + + tcpkali = callPackage ../applications/networking/tcpkali { }; + + tcpreplay = callPackage ../tools/networking/tcpreplay { }; + + ted = callPackage ../tools/typesetting/ted { }; + + teamviewer = libsForQt5.callPackage ../applications/networking/remote/teamviewer { }; + + teleconsole = callPackage ../tools/misc/teleconsole { }; + + telegraf = callPackage ../servers/monitoring/telegraf { }; + + teleport = callPackage ../servers/teleport {}; + + telepresence = callPackage ../tools/networking/telepresence { + pythonPackages = python3Packages; + }; + + termplay = callPackage ../tools/misc/termplay { }; + + testdisk-photorec = callPackage ../tools/system/testdisk-photorec { }; + + tewisay = callPackage ../tools/misc/tewisay { }; + + texmacs = if stdenv.isDarwin + then callPackage ../applications/editors/texmacs/darwin.nix { + inherit (darwin.apple_sdk.frameworks) CoreFoundation Cocoa; + tex = texlive.combined.scheme-small; + extraFonts = true; + } else callPackage ../applications/editors/texmacs { + tex = texlive.combined.scheme-small; + extraFonts = true; + }; + + texmaker = libsForQt5.callPackage ../applications/editors/texmaker { }; + + texstudio = libsForQt5.callPackage ../applications/editors/texstudio { }; + + textadept = callPackage ../applications/editors/textadept { }; + + texworks = callPackage ../applications/editors/texworks { }; + + thc-hydra = callPackage ../tools/security/thc-hydra { }; + + theharvester = callPackage ../tools/security/theharvester { }; + + inherit (nodePackages) thelounge; + + thefuck = python3Packages.callPackage ../tools/misc/thefuck { }; + + thin-provisioning-tools = callPackage ../tools/misc/thin-provisioning-tools { }; + + tiled = libsForQt5.callPackage ../applications/editors/tiled { }; + + timemachine = callPackage ../applications/audio/timemachine { }; + + timelapse-deflicker = callPackage ../applications/graphics/timelapse-deflicker { }; + + timetrap = callPackage ../applications/office/timetrap { }; + + timetable = callPackage ../applications/office/timetable { }; + + tzupdate = callPackage ../applications/misc/tzupdate { }; + + tinc = callPackage ../tools/networking/tinc { }; + + tie = callPackage ../development/tools/misc/tie { }; + + tikzit = libsForQt5.callPackage ../tools/typesetting/tikzit { }; + + tilix = callPackage ../applications/misc/tilix { }; + + tinc_pre = callPackage ../tools/networking/tinc/pre.nix {}; + + tiny8086 = callPackage ../applications/virtualization/8086tiny { }; + + tinyemu = callPackage ../applications/virtualization/tinyemu { }; + + tinyprog = callPackage ../development/tools/misc/tinyprog { }; + + tinyproxy = callPackage ../tools/networking/tinyproxy {}; + + tio = callPackage ../tools/misc/tio { }; + + tldr = callPackage ../tools/misc/tldr { }; + + tldr-hs = haskellPackages.tldr; + + tlspool = callPackage ../tools/networking/tlspool { }; + + tmate = callPackage ../tools/misc/tmate { }; + + tmpwatch = callPackage ../tools/misc/tmpwatch { }; + + tmux = callPackage ../tools/misc/tmux { }; + + tmux-cssh = callPackage ../tools/misc/tmux-cssh { }; + + tmuxp = callPackage ../tools/misc/tmuxp { }; + + tmuxinator = callPackage ../tools/misc/tmuxinator { }; + + tmuxPlugins = recurseIntoAttrs (callPackage ../misc/tmux-plugins { }); + + tmsu = callPackage ../tools/filesystems/tmsu { + go = go_1_10; + }; + + toilet = callPackage ../tools/misc/toilet { }; + + tokei = callPackage ../development/tools/misc/tokei { }; + + toml2nix = (callPackage ../tools/toml2nix { }).toml2nix { }; + + tor = callPackage ../tools/security/tor { + # remove this, when libevent's openssl is upgraded to 1_1_0 or newer. + libevent = libevent.override { + sslSupport = false; + }; + }; + + tor-arm = callPackage ../tools/security/tor/tor-arm.nix { }; + + tor-browser-bundle-bin = callPackage ../applications/networking/browsers/tor-browser-bundle-bin { }; + + tor-browser-bundle = callPackage ../applications/networking/browsers/tor-browser-bundle { + stdenv = stdenvNoCC; + tor-browser-unwrapped = firefoxPackages.tor-browser; + }; + + touchegg = callPackage ../tools/inputmethods/touchegg { }; + + torsocks = callPackage ../tools/security/tor/torsocks.nix { }; + + tox-node = callPackage ../tools/networking/tox-node { }; + + toxvpn = callPackage ../tools/networking/toxvpn { }; + + toybox = callPackage ../tools/misc/toybox { }; + + tpmmanager = callPackage ../applications/misc/tpmmanager { }; + + tpm-quote-tools = callPackage ../tools/security/tpm-quote-tools { }; + + tpm-tools = callPackage ../tools/security/tpm-tools { }; + + tpm-luks = callPackage ../tools/security/tpm-luks { }; + + tpm2-tools = callPackage ../tools/security/tpm2-tools { }; + + trezord = callPackage ../servers/trezord { }; + + tthsum = callPackage ../applications/misc/tthsum { }; + + chaps = callPackage ../tools/security/chaps { }; + + trace-cmd = callPackage ../os-specific/linux/trace-cmd { }; + + kernelshark = libsForQt5.callPackage ../os-specific/linux/trace-cmd/kernelshark.nix { }; + + traceroute = callPackage ../tools/networking/traceroute { }; + + tracebox = callPackage ../tools/networking/tracebox { }; + + tracefilegen = callPackage ../development/tools/analysis/garcosim/tracefilegen { }; + + tracefilesim = callPackage ../development/tools/analysis/garcosim/tracefilesim { }; + + transifex-client = python3.pkgs.callPackage ../tools/text/transifex-client { }; + + translate-shell = callPackage ../applications/misc/translate-shell { }; + + transporter = callPackage ../applications/networking/transporter { }; + + trash-cli = callPackage ../tools/misc/trash-cli { }; + + trickle = callPackage ../tools/networking/trickle {}; + + inherit (nodePackages) triton; + + triggerhappy = callPackage ../tools/inputmethods/triggerhappy {}; + + trilium = callPackage ../applications/office/trilium { }; + + trousers = callPackage ../tools/security/trousers { + openssl = openssl_1_0_2; + }; + + trx = callPackage ../tools/audio/trx { }; + + tryton = callPackage ../applications/office/tryton { }; + + trytond = callPackage ../applications/office/trytond { }; + + omapd = callPackage ../tools/security/omapd { }; + + ttf2pt1 = callPackage ../tools/misc/ttf2pt1 { }; + + ttfautohint = libsForQt5.callPackage ../tools/misc/ttfautohint { }; + ttfautohint-nox = ttfautohint.override { enableGUI = false; }; + + tty-clock = callPackage ../tools/misc/tty-clock { }; + + ttyplot = callPackage ../tools/misc/ttyplot { }; + + ttyrec = callPackage ../tools/misc/ttyrec { }; + + ttylog = callPackage ../tools/misc/ttylog { }; + + turses = callPackage ../applications/networking/instant-messengers/turses { }; + + oysttyer = callPackage ../applications/networking/instant-messengers/oysttyer { }; + + twilight = callPackage ../tools/graphics/twilight { + libX11 = xorg.libX11; + }; + + twitterBootstrap = callPackage ../development/web/twitter-bootstrap {}; + + txr = callPackage ../tools/misc/txr { stdenv = clangStdenv; }; + + txt2man = callPackage ../tools/misc/txt2man { }; + + txt2tags = callPackage ../tools/text/txt2tags { }; + + txtw = callPackage ../tools/misc/txtw { }; + + u9fs = callPackage ../servers/u9fs { }; + + ua = callPackage ../tools/networking/ua { }; + + ubridge = callPackage ../tools/networking/ubridge { }; + + ucl = callPackage ../development/libraries/ucl { }; + + ucspi-tcp = callPackage ../tools/networking/ucspi-tcp { }; + + udftools = callPackage ../tools/filesystems/udftools {}; + + udpt = callPackage ../servers/udpt { }; + + udptunnel = callPackage ../tools/networking/udptunnel { }; + + ufraw = callPackage ../applications/graphics/ufraw { + stdenv = gcc6Stdenv; # doesn't build with gcc7 + }; + + uftrace = callPackage ../development/tools/uftrace { }; + + uget = callPackage ../tools/networking/uget { }; + + uget-integrator = callPackage ../tools/networking/uget-integrator { }; + + uif2iso = callPackage ../tools/cd-dvd/uif2iso { }; + + umlet = callPackage ../tools/misc/umlet { }; + + unetbootin = callPackage ../tools/cd-dvd/unetbootin { }; + + unfs3 = callPackage ../servers/unfs3 { }; + + unoconv = callPackage ../tools/text/unoconv { }; + + unrtf = callPackage ../tools/text/unrtf { }; + + untex = callPackage ../tools/text/untex { }; + + untrunc = callPackage ../tools/video/untrunc { }; + + up = callPackage ../tools/misc/up { }; + + upx = callPackage ../tools/compression/upx { }; + + uqmi = callPackage ../tools/networking/uqmi { }; + + uriparser = callPackage ../development/libraries/uriparser {}; + + urlscan = callPackage ../applications/misc/urlscan { }; + + urlview = callPackage ../applications/misc/urlview {}; + + usbmuxd = callPackage ../tools/misc/usbmuxd {}; + + usync = callPackage ../applications/misc/usync { }; + + uwsgi = callPackage ../servers/uwsgi { }; + + vacuum = callPackage ../applications/networking/instant-messengers/vacuum {}; + + vampire = callPackage ../applications/science/logic/vampire {}; + + vdmfec = callPackage ../applications/backup/vdmfec {}; + + vk-messenger = callPackage ../applications/networking/instant-messengers/vk-messenger {}; + + volatility = callPackage ../tools/security/volatility { }; + + vbetool = callPackage ../tools/system/vbetool { }; + + vde2 = callPackage ../tools/networking/vde2 { + openssl = openssl_1_0_2; + }; + + vboot_reference = callPackage ../tools/system/vboot_reference {}; + + vcftools = callPackage ../applications/science/biology/vcftools { }; + + vcsh = callPackage ../applications/version-management/vcsh { }; + + vcs_query = callPackage ../tools/misc/vcs_query { }; + + vcstool = callPackage ../development/tools/vcstool { }; + + verilator = callPackage ../applications/science/electronics/verilator {}; + + verilog = callPackage ../applications/science/electronics/verilog {}; + + video2midi = callPackage ../tools/audio/video2midi { + pythonPackages = python3Packages; + }; + + vifm = callPackage ../applications/misc/vifm { }; + + viking = callPackage ../applications/misc/viking { + inherit (gnome2) scrollkeeper; + }; + + vim-vint = callPackage ../development/tools/vim-vint { }; + + vimer = callPackage ../tools/misc/vimer { }; + + vimpager = callPackage ../tools/misc/vimpager { }; + vimpager-latest = callPackage ../tools/misc/vimpager/latest.nix { }; + + visidata = (newScope python3Packages) ../applications/misc/visidata { + }; + + vit = callPackage ../applications/misc/vit { }; + + viu = callPackage ../tools/graphics/viu { }; + + vnc2flv = callPackage ../tools/video/vnc2flv {}; + + vncrec = callPackage ../tools/video/vncrec { }; + + vo-amrwbenc = callPackage ../development/libraries/vo-amrwbenc { }; + + vobcopy = callPackage ../tools/cd-dvd/vobcopy { }; + + vobsub2srt = callPackage ../tools/cd-dvd/vobsub2srt { }; + + void = callPackage ../tools/misc/void { }; + + volume_key = callPackage ../development/libraries/volume-key { }; + + vorbisgain = callPackage ../tools/misc/vorbisgain { }; + + vpnc = callPackage ../tools/networking/vpnc { }; + + vp = callPackage ../applications/misc/vp { + # Enable next line for console graphics. Note that + # it requires `sixel` enabled terminals such as mlterm + # or xterm -ti 340 + SDL = SDL_sixel; + }; + + openconnect_pa = callPackage ../tools/networking/openconnect_pa { + openssl = null; + }; + + openconnect = openconnect_gnutls; + + openconnect_openssl = callPackage ../tools/networking/openconnect { + gnutls = null; + }; + + openconnect_gnutls = callPackage ../tools/networking/openconnect { + openssl = null; + }; + + ding-libs = callPackage ../tools/misc/ding-libs { }; + + sssd = callPackage ../os-specific/linux/sssd { + inherit (perlPackages) Po4a; + inherit (python27Packages) ldap; + }; + + vtun = callPackage ../tools/networking/vtun { + openssl = openssl_1_0_2; + }; + + waifu2x-converter-cpp = callPackage ../tools/graphics/waifu2x-converter-cpp { }; + + wakatime = pythonPackages.callPackage ../tools/misc/wakatime { }; + + weather = callPackage ../applications/misc/weather { }; + + wego = callPackage ../applications/misc/wego { }; + + wal_e = callPackage ../tools/backup/wal-e { }; + + wasabiwallet = callPackage ../applications/altcoins/wasabiwallet { }; + + watchexec = callPackage ../tools/misc/watchexec { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + watchman = callPackage ../development/tools/watchman { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + wavefunctioncollapse = callPackage ../tools/graphics/wavefunctioncollapse {}; + + wbox = callPackage ../tools/networking/wbox {}; + + webassemblyjs-cli = nodePackages."@webassemblyjs/cli"; + webassemblyjs-repl = nodePackages."@webassemblyjs/repl"; + wasm-strip = nodePackages."@webassemblyjs/wasm-strip"; + wasm-text-gen = nodePackages."@webassemblyjs/wasm-text-gen"; + wast-refmt = nodePackages."@webassemblyjs/wast-refmt"; + + welkin = callPackage ../tools/graphics/welkin {}; + + wf-recorder = callPackage ../applications/video/wf-recorder { }; + + whipper = callPackage ../applications/audio/whipper { }; + + whois = callPackage ../tools/networking/whois { }; + + wireguard-tools = callPackage ../tools/networking/wireguard-tools { }; + + woff2 = callPackage ../development/web/woff2 { }; + + woof = callPackage ../tools/misc/woof { }; + + wpscan = callPackage ../tools/security/wpscan { }; + + wsmancli = callPackage ../tools/system/wsmancli {}; + + wolfebin = callPackage ../tools/networking/wolfebin { + python = python2; + }; + + xautoclick = callPackage ../applications/misc/xautoclick {}; + + xl2tpd = callPackage ../tools/networking/xl2tpd { }; + + xe = callPackage ../tools/system/xe { }; + + testdisk = callPackage ../tools/misc/testdisk { }; + + textql = callPackage ../development/tools/textql { }; + + html2text = callPackage ../tools/text/html2text { }; + + html-tidy = callPackage ../tools/text/html-tidy { }; + + html-xml-utils = callPackage ../tools/text/xml/html-xml-utils { }; + + htmldoc = callPackage ../tools/typesetting/htmldoc { + inherit (darwin.apple_sdk.frameworks) SystemConfiguration Foundation; + }; + + rcm = callPackage ../tools/misc/rcm {}; + + td = callPackage ../tools/misc/td { }; + + tegola = callPackage ../servers/tegola {}; + + tftp-hpa = callPackage ../tools/networking/tftp-hpa {}; + + tigervnc = callPackage ../tools/admin/tigervnc { + fontDirectories = [ xorg.fontadobe75dpi xorg.fontmiscmisc xorg.fontcursormisc xorg.fontbhlucidatypewriter75dpi ]; + }; + + tightvnc = callPackage ../tools/admin/tightvnc { + fontDirectories = [ xorg.fontadobe75dpi xorg.fontmiscmisc xorg.fontcursormisc + xorg.fontbhlucidatypewriter75dpi ]; + }; + + time = callPackage ../tools/misc/time { }; + + tweet-hs = haskell.lib.justStaticExecutables haskellPackages.tweet-hs; + + qfsm = callPackage ../applications/science/electronics/qfsm { }; + + tkgate = callPackage ../applications/science/electronics/tkgate/1.x.nix { }; + + tm = callPackage ../tools/system/tm { }; + + tradcpp = callPackage ../development/tools/tradcpp { }; + + tre = callPackage ../development/libraries/tre { }; + + ts = callPackage ../tools/system/ts { }; + + transfig = callPackage ../tools/graphics/transfig { + libpng = libpng12; + }; + + ttmkfdir = callPackage ../tools/misc/ttmkfdir { }; + + ttwatch = callPackage ../tools/misc/ttwatch { }; + + udunits = callPackage ../development/libraries/udunits { }; + + uemacs = callPackage ../applications/editors/uemacs { }; + + uftp = callPackage ../servers/uftp {}; + + uhttpmock = callPackage ../development/libraries/uhttpmock { }; + + uim = callPackage ../tools/inputmethods/uim { }; + + uhub = callPackage ../servers/uhub { }; + + unclutter = callPackage ../tools/misc/unclutter { }; + + unclutter-xfixes = callPackage ../tools/misc/unclutter-xfixes { }; + + unbound = callPackage ../tools/networking/unbound { }; + + units = callPackage ../tools/misc/units { }; + + unittest-cpp = callPackage ../development/libraries/unittest-cpp { }; + + unrar = callPackage ../tools/archivers/unrar { }; + + xar = callPackage ../tools/compression/xar { }; + + xarchive = callPackage ../tools/archivers/xarchive { }; + + xarchiver = callPackage ../tools/archivers/xarchiver { }; + + xbanish = callPackage ../tools/X11/xbanish { }; + + xbill = callPackage ../games/xbill { }; + + xbrightness = callPackage ../tools/X11/xbrightness { }; + + xkbvalidate = callPackage ../tools/X11/xkbvalidate { }; + + xfstests = callPackage ../tools/misc/xfstests { }; + + xprintidle-ng = callPackage ../tools/X11/xprintidle-ng {}; + + xscast = callPackage ../applications/video/xscast { }; + + xsettingsd = callPackage ../tools/X11/xsettingsd { }; + + xsensors = callPackage ../os-specific/linux/xsensors { }; + + xcruiser = callPackage ../applications/misc/xcruiser { }; + + xxkb = callPackage ../applications/misc/xxkb { }; + + ugarit = callPackage ../tools/backup/ugarit { }; + + ugarit-manifest-maker = callPackage ../tools/backup/ugarit-manifest-maker { }; + + unar = callPackage ../tools/archivers/unar { stdenv = clangStdenv; }; + + unarj = callPackage ../tools/archivers/unarj { }; + + unp = callPackage ../tools/archivers/unp { }; + + unshield = callPackage ../tools/archivers/unshield { }; + + unzip = callPackage ../tools/archivers/unzip { }; + + unzipNLS = lowPrio (unzip.override { enableNLS = true; }); + + undmg = callPackage ../tools/archivers/undmg { }; + + uptimed = callPackage ../tools/system/uptimed { }; + + urjtag = callPackage ../tools/misc/urjtag { }; + + urlwatch = callPackage ../tools/networking/urlwatch { }; + + valum = callPackage ../development/web/valum { }; + + inherit (callPackages ../servers/varnish { }) + varnish4 varnish5 varnish6; + inherit (callPackages ../servers/varnish/packages.nix { }) + varnish4Packages + varnish5Packages + varnish6Packages; + + varnishPackages = varnish5Packages; + varnish = varnishPackages.varnish; + + hitch = callPackage ../servers/hitch { }; + + venus = callPackage ../tools/misc/venus { + python = python27; + }; + + veracrypt = callPackage ../applications/misc/veracrypt { + wxGTK = wxGTK30; + }; + + vlan = callPackage ../tools/networking/vlan { }; + + vmtouch = callPackage ../tools/misc/vmtouch { }; + + vncdo = callPackage ../tools/admin/vncdo { }; + + volumeicon = callPackage ../tools/audio/volumeicon { }; + + waf = callPackage ../development/tools/build-managers/waf { python = python3; }; + wafHook = callPackage ../development/tools/build-managers/wafHook { }; + + wakelan = callPackage ../tools/networking/wakelan { }; + + wavemon = callPackage ../tools/networking/wavemon { }; + + wdfs = callPackage ../tools/filesystems/wdfs { }; + + wdiff = callPackage ../tools/text/wdiff { }; + + webalizer = callPackage ../tools/networking/webalizer { }; + + weighttp = callPackage ../tools/networking/weighttp { }; + + wget = callPackage ../tools/networking/wget { + libpsl = null; + }; + + which = callPackage ../tools/system/which { }; + + woeusb = callPackage ../tools/misc/woeusb { }; + + chase = callPackage ../tools/system/chase { }; + + wicd = callPackage ../tools/networking/wicd { }; + + wimlib = callPackage ../tools/archivers/wimlib { }; + + wipe = callPackage ../tools/security/wipe { }; + + wireguard-go = callPackage ../tools/networking/wireguard-go { }; + + wkhtmltopdf = libsForQt5.callPackage ../tools/graphics/wkhtmltopdf { }; + + wml = callPackage ../development/web/wml { }; + + wmc-mpris = callPackage ../applications/misc/web-media-controller { }; + + wol = callPackage ../tools/networking/wol { }; + + wolf-shaper = callPackage ../applications/audio/wolf-shaper { }; + + wpgtk = callPackage ../tools/X11/wpgtk { }; + + wring = nodePackages.wring; + + wrk = callPackage ../tools/networking/wrk { }; + + wrk2 = callPackage ../tools/networking/wrk2 { }; + + wuzz = callPackage ../tools/networking/wuzz { }; + + wv = callPackage ../tools/misc/wv { }; + + wv2 = callPackage ../tools/misc/wv2 { }; + + wyrd = callPackage ../tools/misc/wyrd { + ocamlPackages = ocaml-ng.ocamlPackages_4_05; + }; + + x86info = callPackage ../os-specific/linux/x86info { }; + + x11_ssh_askpass = callPackage ../tools/networking/x11-ssh-askpass { }; + + xbursttools = callPackage ../tools/misc/xburst-tools { + # It needs a cross compiler for mipsel to build the firmware it will + # load into the Ben Nanonote + gccCross = pkgsCross.ben-nanonote.buildPackages.gccCrossStageStatic; + }; + + clipnotify = callPackage ../tools/misc/clipnotify { }; + + xclip = callPackage ../tools/misc/xclip { }; + + xcur2png = callPackage ../tools/graphics/xcur2png { }; + + xcwd = callPackage ../tools/X11/xcwd { }; + + xtitle = callPackage ../tools/misc/xtitle { }; + + xdelta = callPackage ../tools/compression/xdelta { }; + xdeltaUnstable = callPackage ../tools/compression/xdelta/unstable.nix { }; + + xdummy = callPackage ../tools/misc/xdummy { }; + + xdxf2slob = callPackage ../tools/misc/xdxf2slob { }; + + xe-guest-utilities = callPackage ../tools/virtualization/xe-guest-utilities { }; + + xflux = callPackage ../tools/misc/xflux { }; + xflux-gui = callPackage ../tools/misc/xflux/gui.nix { + gnome_python = gnome2.gnome_python; + }; + + xfsprogs = callPackage ../tools/filesystems/xfsprogs { }; + libxfs = xfsprogs.dev; + + xml2 = callPackage ../tools/text/xml/xml2 { }; + + xmlformat = callPackage ../tools/text/xml/xmlformat { }; + + xmlroff = callPackage ../tools/typesetting/xmlroff { }; + + xmloscopy = callPackage ../tools/text/xml/xmloscopy { }; + + xmlstarlet = callPackage ../tools/text/xml/xmlstarlet { }; + + xmlto = callPackage ../tools/typesetting/xmlto { + w3m = w3m-batch; + }; + + xmpppy = pythonPackages.xmpppy; + + xiccd = callPackage ../tools/misc/xiccd { }; + + xidlehook = callPackage ../tools/X11/xidlehook { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + xorriso = callPackage ../tools/cd-dvd/xorriso { }; + + xpf = callPackage ../tools/text/xml/xpf { + libxml2 = libxml2Python; + }; + + xsecurelock = callPackage ../tools/X11/xsecurelock { + xset = xorg.xset; + }; + + xsel = callPackage ../tools/misc/xsel { }; + + xsv = callPackage ../tools/text/xsv { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + xtreemfs = callPackage ../tools/filesystems/xtreemfs { + boost = boost165; + }; + + xurls = callPackage ../tools/text/xurls {}; + + xv = callPackage ../tools/misc/xv {}; + + xvfb_run = callPackage ../tools/misc/xvfb-run { inherit (texFunctions) fontsConf; }; + + xvkbd = callPackage ../tools/X11/xvkbd {}; + + xwinmosaic = callPackage ../tools/X11/xwinmosaic {}; + + xwinwrap = callPackage ../tools/X11/xwinwrap {}; + + yafaray-core = callPackage ../tools/graphics/yafaray-core { }; + + yaft = callPackage ../applications/misc/yaft { }; + + yarn = callPackage ../development/tools/yarn { }; + + yarn2nix-moretea = callPackage ../development/tools/yarn2nix-moretea/yarn2nix { }; + + yasr = callPackage ../applications/audio/yasr { }; + + yank = callPackage ../tools/misc/yank { }; + + yaml-merge = callPackage ../tools/text/yaml-merge { }; + + yeshup = callPackage ../tools/system/yeshup { }; + + # To expose more packages for Yi, override the extraPackages arg. + yi = callPackage ../applications/editors/yi/wrapper.nix { }; + + yj = callPackage ../development/tools/yj { }; + + yle-dl = callPackage ../tools/misc/yle-dl {}; + + you-get = python3Packages.callPackage ../tools/misc/you-get { }; + + zbackup = callPackage ../tools/backup/zbackup {}; + + zbar = callPackage ../tools/graphics/zbar { }; + + zdelta = callPackage ../tools/compression/zdelta { }; + + zerotierone = callPackage ../tools/networking/zerotierone { }; + + zerofree = callPackage ../tools/filesystems/zerofree { }; + + zfstools = callPackage ../tools/filesystems/zfstools { }; + + zile = callPackage ../applications/editors/zile { }; + + zinnia = callPackage ../tools/inputmethods/zinnia { }; + tegaki-zinnia-japanese = callPackage ../tools/inputmethods/tegaki-zinnia-japanese { }; + + zimreader = callPackage ../tools/text/zimreader { }; + + zimwriterfs = callPackage ../tools/text/zimwriterfs { }; + + par = callPackage ../tools/text/par { }; + + zip = callPackage ../tools/archivers/zip { }; + + zkfuse = callPackage ../tools/filesystems/zkfuse { }; + + zpaq = callPackage ../tools/archivers/zpaq { }; + zpaqd = callPackage ../tools/archivers/zpaq/zpaqd.nix { }; + + zsh-autoenv = callPackage ../tools/misc/zsh-autoenv { }; + + zsh-git-prompt = callPackage ../shells/zsh/zsh-git-prompt { }; + + zsh-history-substring-search = callPackage ../shells/zsh/zsh-history-substring-search { }; + + zsh-navigation-tools = callPackage ../tools/misc/zsh-navigation-tools { }; + + zsh-syntax-highlighting = callPackage ../shells/zsh/zsh-syntax-highlighting { }; + + zsh-autosuggestions = callPackage ../shells/zsh/zsh-autosuggestions { }; + + zsh-powerlevel9k = callPackage ../shells/zsh/zsh-powerlevel9k { }; + + zsh-command-time = callPackage ../shells/zsh/zsh-command-time { }; + + zsh-you-should-use = callPackage ../shells/zsh/zsh-you-should-use { }; + + zssh = callPackage ../tools/networking/zssh { }; + + zstd = callPackage ../tools/compression/zstd { }; + + zsync = callPackage ../tools/compression/zsync { }; + + zxing = callPackage ../tools/graphics/zxing {}; + + zmap = callPackage ../tools/security/zmap { }; + + + ### SHELLS + + runtimeShell = "${runtimeShellPackage}${runtimeShellPackage.shellPath}"; + runtimeShellPackage = bash; + + any-nix-shell = callPackage ../shells/any-nix-shell { }; + + bash = lowPrio (callPackage ../shells/bash/4.4.nix { }); + bash_5 = lowPrio (callPackage ../shells/bash/5.0.nix { }); + bashInteractive_5 = lowPrio (callPackage ../shells/bash/5.0.nix { + interactive = true; + withDocs = true; + }); + + # WARNING: this attribute is used by nix-shell so it shouldn't be removed/renamed + bashInteractive = callPackage ../shells/bash/4.4.nix { + interactive = true; + withDocs = true; + }; + + bash-completion = callPackage ../shells/bash/bash-completion { }; + + gradle-completion = callPackage ../shells/zsh/gradle-completion { }; + + nix-bash-completions = callPackage ../shells/bash/nix-bash-completions { }; + + dash = callPackage ../shells/dash { }; + + dasht = callPackage ../tools/misc/dasht { }; + + dashing = callPackage ../tools/misc/dashing { }; + + es = callPackage ../shells/es { }; + + fish = callPackage ../shells/fish { }; + + fish-foreign-env = callPackage ../shells/fish/fish-foreign-env { }; + + ion = callPackage ../shells/ion { }; + + jush = callPackage ../shells/jush { }; + + ksh = callPackage ../shells/ksh { }; + + mksh = callPackage ../shells/mksh { }; + + oh = callPackage ../shells/oh { }; + + oil = callPackage ../shells/oil { }; + + pash = callPackage ../shells/pash { }; + + tcsh = callPackage ../shells/tcsh { }; + + rssh = callPackage ../shells/rssh { }; + + rush = callPackage ../shells/rush { }; + + xonsh = callPackage ../shells/xonsh { }; + + zsh = callPackage ../shells/zsh { }; + + nix-zsh-completions = callPackage ../shells/zsh/nix-zsh-completions { }; + + zsh-completions = callPackage ../shells/zsh/zsh-completions { }; + + zsh-prezto = callPackage ../shells/zsh/zsh-prezto { }; + + grml-zsh-config = callPackage ../shells/zsh/grml-zsh-config { }; + + + ### DEVELOPMENT / COMPILERS + + abcl = callPackage ../development/compilers/abcl {}; + + adoptopenjdk-bin-11-packages-linux = import ../development/compilers/adoptopenjdk-bin/jdk11-linux.nix; + adoptopenjdk-bin-11-packages-darwin = import ../development/compilers/adoptopenjdk-bin/jdk11-darwin.nix; + + adoptopenjdk-hotspot-bin-11 = if stdenv.isLinux + then callPackage adoptopenjdk-bin-11-packages-linux.jdk-hotspot {} + else callPackage adoptopenjdk-bin-11-packages-darwin.jdk-hotspot {}; + adoptopenjdk-jre-hotspot-bin-11 = if stdenv.isLinux + then callPackage adoptopenjdk-bin-11-packages-linux.jre-hotspot {} + else callPackage adoptopenjdk-bin-11-packages-darwin.jre-hotspot {}; + + adoptopenjdk-openj9-bin-11 = if stdenv.isLinux + then callPackage adoptopenjdk-bin-11-packages-linux.jdk-openj9 {} + else callPackage adoptopenjdk-bin-11-packages-darwin.jdk-openj9 {}; + + adoptopenjdk-jre-openj9-bin-11 = if stdenv.isLinux + then callPackage adoptopenjdk-bin-11-packages-linux.jre-openj9 {} + else callPackage adoptopenjdk-bin-11-packages-darwin.jre-openj9 {}; + + adoptopenjdk-bin = adoptopenjdk-hotspot-bin-11; + adoptopenjdk-jre-bin = adoptopenjdk-jre-hotspot-bin-11; + + adoptopenjdk-icedtea-web = callPackage ../development/compilers/adoptopenjdk-icedtea-web { + jdk = jdk8; + }; + + aldor = callPackage ../development/compilers/aldor { }; + + aliceml = callPackage ../development/compilers/aliceml { }; + + arachne-pnr = callPackage ../development/compilers/arachne-pnr { }; + + asn1c = callPackage ../development/compilers/asn1c { }; + + aspectj = callPackage ../development/compilers/aspectj { }; + + ats = callPackage ../development/compilers/ats { }; + ats2 = callPackage ../development/compilers/ats2 { }; + + avra = callPackage ../development/compilers/avra { }; + + avian = callPackage ../development/compilers/avian { + inherit (darwin.apple_sdk.frameworks) CoreServices Foundation; + stdenv = if stdenv.cc.isGNU then gcc49Stdenv else stdenv; + }; + + bigloo = callPackage ../development/compilers/bigloo { }; + + binaryen = callPackage ../development/compilers/binaryen { }; + + colm = callPackage ../development/compilers/colm { }; + + chickenPackages_4 = callPackage ../development/compilers/chicken/4 { }; + chickenPackages_5 = callPackage ../development/compilers/chicken/5 { }; + chickenPackages = chickenPackages_5; + + inherit (chickenPackages) + fetchegg + eggDerivation + chicken + egg2nix; + + ccl = callPackage ../development/compilers/ccl { + inherit (buildPackages.darwin) bootstrap_cmds; + }; + + cdb = callPackage ../development/tools/database/cdb { + stdenv = gccStdenv; + }; + + chez = callPackage ../development/compilers/chez { + inherit (darwin) cctools; + }; + + clang = llvmPackages.clang; + clang-manpages = llvmPackages.clang-manpages; + + clang-sierraHack = clang.override { + name = "clang-wrapper-with-reexport-hack"; + bintools = darwin.binutils.override { + useMacosReexportHack = true; + }; + }; + llvm-polly = llvmPackages_latest.llvm-polly; + clang-polly = llvmPackages_latest.clang.override { cc = llvmPackages_latest.clang-polly-unwrapped; }; + + clang_8 = llvmPackages_8.clang; + clang_7 = llvmPackages_7.clang; + clang_6 = llvmPackages_6.clang; + clang_5 = llvmPackages_5.clang; + clang_4 = llvmPackages_4.clang; + clang_39 = llvmPackages_39.clang; + clang_38 = llvmPackages_38.clang; + clang_35 = wrapCC llvmPackages_35.clang; + + clang-tools = callPackage ../development/tools/clang-tools { + llvmPackages = llvmPackages_latest; + }; + + clang-analyzer = callPackage ../development/tools/analysis/clang-analyzer { }; + + #Use this instead of stdenv to build with clang + clangStdenv = if stdenv.cc.isClang then stdenv else lowPrio llvmPackages.stdenv; + clang-sierraHack-stdenv = overrideCC stdenv buildPackages.clang-sierraHack; + libcxxStdenv = if stdenv.isDarwin then stdenv else lowPrio llvmPackages.libcxxStdenv; + + clasp-common-lisp = callPackage ../development/compilers/clasp { + llvmPackages = llvmPackages_6; + stdenv = llvmPackages_6.stdenv; + }; + + clean = callPackage ../development/compilers/clean { }; + + closurecompiler = callPackage ../development/compilers/closure { }; + + cmdstan = callPackage ../development/compilers/cmdstan { }; + + cmucl_binary = pkgsi686Linux.callPackage ../development/compilers/cmucl/binary.nix { }; + + compcert = callPackage ../development/compilers/compcert { }; + + cryptol = haskell.lib.justStaticExecutables haskellPackages.cryptol; + + inherit (callPackages ../development/compilers/crystal { + stdenv = if stdenv.cc.isClang then llvmPackages_6.stdenv else stdenv; + inherit (llvmPackages_6) clang llvm; + }) + crystal_0_25 + crystal_0_26 + crystal_0_27 + crystal_0_29 + crystal; + + icr = callPackage ../development/tools/icr {}; + + scry = callPackage ../development/tools/scry {}; + + dbmate = callPackage ../development/tools/database/dbmate { }; + + devpi-client = callPackage ../development/tools/devpi-client {}; + + devpi-server = callPackage ../development/tools/devpi-server {}; + + dotty = callPackage ../development/compilers/scala/dotty.nix { jre = jre8;}; + + drumstick = callPackage ../development/libraries/drumstick { }; + + ecl = callPackage ../development/compilers/ecl { }; + ecl_16_1_2 = callPackage ../development/compilers/ecl/16.1.2.nix { }; + + eli = callPackage ../development/compilers/eli { }; + + eql = callPackage ../development/compilers/eql {}; + + elm2nix = haskell.lib.justStaticExecutables haskellPackages.elm2nix; + + elmPackages = recurseIntoAttrs (callPackage ../development/compilers/elm { }); + + apache-flex-sdk = callPackage ../development/compilers/apache-flex-sdk { }; + + fasm = pkgsi686Linux.callPackage ../development/compilers/fasm { + inherit (stdenv) isx86_64; + }; + fasm-bin = callPackage ../development/compilers/fasm/bin.nix { }; + + fpc = callPackage ../development/compilers/fpc { }; + + gambit = callPackage ../development/compilers/gambit { stdenv = gccStdenv; }; + gambit-unstable = callPackage ../development/compilers/gambit/unstable.nix { stdenv = gccStdenv; }; + gerbil = callPackage ../development/compilers/gerbil { stdenv = gccStdenv; }; + gerbil-unstable = callPackage ../development/compilers/gerbil/unstable.nix { stdenv = gccStdenv; }; + + gccFun = callPackage ../development/compilers/gcc/7; + gcc = gcc7; + gcc-unwrapped = gcc.cc; + + gccStdenv = if stdenv.cc.isGNU then stdenv else stdenv.override { + allowedRequisites = null; + cc = gcc; + # Remove libcxx/libcxxabi, and add clang for AS if on darwin (it uses + # clang's internal assembler). + extraBuildInputs = lib.optional stdenv.hostPlatform.isDarwin clang.cc; + }; + + gcc49Stdenv = overrideCC gccStdenv buildPackages.gcc49; + gcc5Stdenv = overrideCC gccStdenv buildPackages.gcc5; + gcc6Stdenv = overrideCC gccStdenv buildPackages.gcc6; + gcc7Stdenv = overrideCC gccStdenv buildPackages.gcc7; + gcc8Stdenv = overrideCC gccStdenv buildPackages.gcc8; + gcc9Stdenv = overrideCC gccStdenv buildPackages.gcc9; + + wrapCCMulti = cc: + if stdenv.targetPlatform.system == "x86_64-linux" then let + # Binutils with glibc multi + bintools = cc.bintools.override { + libc = glibc_multi; + }; + in lowPrio (wrapCCWith { + cc = cc.cc.override { + stdenv = overrideCC stdenv (wrapCCWith { + cc = cc.cc; + inherit bintools; + libc = glibc_multi; + }); + profiledCompiler = false; + enableMultilib = true; + }; + libc = glibc_multi; + inherit bintools; + extraBuildCommands = '' + echo "dontMoveLib64=1" >> $out/nix-support/setup-hook + ''; + }) else throw "Multilib ${cc.name} not supported for ‘${stdenv.targetPlatform.system}’"; + + wrapClangMulti = clang: + if stdenv.targetPlatform.system == "x86_64-linux" then + callPackage ../development/compilers/llvm/multi.nix { + inherit clang; + gcc32 = pkgsi686Linux.gcc; + gcc64 = pkgs.gcc; + } + else throw "Multilib ${clang.cc.name} not supported for '${stdenv.targetPlatform.system}'"; + + gcc_multi = wrapCCMulti gcc; + clang_multi = wrapClangMulti clang; + + gccMultiStdenv = overrideCC stdenv buildPackages.gcc_multi; + clangMultiStdenv = overrideCC stdenv buildPackages.clang_multi; + multiStdenv = if stdenv.cc.isClang then clangMultiStdenv else gccMultiStdenv; + + gcc_debug = lowPrio (wrapCC (gcc.cc.override { + stripped = false; + })); + + libstdcxxHook = makeSetupHook + { substitutions = { gcc = gcc-unwrapped; }; } + ../development/compilers/gcc/libstdc++-hook.sh; + + crossLibcStdenv = overrideCC stdenv + (if stdenv.targetPlatform.useLLVM or false + then buildPackages.llvmPackages_8.lldClangNoLibc + else buildPackages.gccCrossStageStatic); + + # The GCC used to build libc for the target platform. Normal gccs will be + # built with, and use, that cross-compiled libc. + gccCrossStageStatic = assert stdenv.targetPlatform != stdenv.hostPlatform; let + libcCross1 = + if stdenv.targetPlatform.libc == "msvcrt" then targetPackages.windows.mingw_w64_headers + else if stdenv.targetPlatform.libc == "libSystem" then darwin.xcode + else if stdenv.targetPlatform.libc == "nblibc" then netbsd.headers + else null; + binutils1 = wrapBintoolsWith { + bintools = binutils-unwrapped; + libc = libcCross1; + }; + in wrapCCWith { + cc = gccFun { + # copy-pasted + inherit noSysDirs; + # PGO seems to speed up compilation by gcc by ~10%, see #445 discussion + profiledCompiler = with stdenv; (!isDarwin && (isi686 || isx86_64)); + isl = if !stdenv.isDarwin then isl_0_17 else null; + + # just for stage static + crossStageStatic = true; + langCC = false; + libcCross = libcCross1; + targetPackages.stdenv.cc.bintools = binutils1; + enableShared = false; + }; + bintools = binutils1; + libc = libcCross1; + }; + + gcc48 = lowPrio (wrapCC (callPackage ../development/compilers/gcc/4.8 { + inherit noSysDirs; + + # PGO seems to speed up compilation by gcc by ~10%, see #445 discussion + profiledCompiler = with stdenv; (!isSunOS && !isDarwin && (isi686 || isx86_64)); + + libcCross = if stdenv.targetPlatform != stdenv.buildPlatform then libcCross else null; + + isl = if !stdenv.isDarwin then isl_0_14 else null; + cloog = if !stdenv.isDarwin then cloog else null; + texinfo = texinfo5; # doesn't validate since 6.1 -> 6.3 bump + })); + + gcc49 = lowPrio (wrapCC (callPackage ../development/compilers/gcc/4.9 { + inherit noSysDirs; + + # PGO seems to speed up compilation by gcc by ~10%, see #445 discussion + profiledCompiler = with stdenv; (!isDarwin && (isi686 || isx86_64)); + + libcCross = if stdenv.targetPlatform != stdenv.buildPlatform then libcCross else null; + + isl = if !stdenv.isDarwin then isl_0_11 else null; + + cloog = if !stdenv.isDarwin then cloog_0_18_0 else null; + })); + + gcc5 = lowPrio (wrapCC (callPackage ../development/compilers/gcc/5 { + inherit noSysDirs; + + # PGO seems to speed up compilation by gcc by ~10%, see #445 discussion + profiledCompiler = with stdenv; (!isDarwin && (isi686 || isx86_64)); + + libcCross = if stdenv.targetPlatform != stdenv.buildPlatform then libcCross else null; + + isl = if !stdenv.isDarwin then isl_0_14 else null; + })); + + gcc6 = lowPrio (wrapCC (callPackage ../development/compilers/gcc/6 { + inherit noSysDirs; + + # PGO seems to speed up compilation by gcc by ~10%, see #445 discussion + profiledCompiler = with stdenv; (!isDarwin && (isi686 || isx86_64)); + + libcCross = if stdenv.targetPlatform != stdenv.buildPlatform then libcCross else null; + + isl = if !stdenv.isDarwin then isl_0_14 else null; + })); + + gcc7 = lowPrio (wrapCC (callPackage ../development/compilers/gcc/7 { + inherit noSysDirs; + + # PGO seems to speed up compilation by gcc by ~10%, see #445 discussion + profiledCompiler = with stdenv; (!isDarwin && (isi686 || isx86_64)); + + libcCross = if stdenv.targetPlatform != stdenv.buildPlatform then libcCross else null; + + isl = if !stdenv.isDarwin then isl_0_17 else null; + })); + + gcc8 = lowPrio (wrapCC (callPackage ../development/compilers/gcc/8 { + inherit noSysDirs; + + # PGO seems to speed up compilation by gcc by ~10%, see #445 discussion + profiledCompiler = with stdenv; (!isDarwin && (isi686 || isx86_64)); + + libcCross = if stdenv.targetPlatform != stdenv.buildPlatform then libcCross else null; + + isl = if !stdenv.isDarwin then isl_0_17 else null; + })); + + gcc9 = lowPrio (wrapCC (callPackage ../development/compilers/gcc/9 { + inherit noSysDirs; + + # PGO seems to speed up compilation by gcc by ~10%, see #445 discussion + profiledCompiler = with stdenv; (!isDarwin && (isi686 || isx86_64)); + + libcCross = if stdenv.targetPlatform != stdenv.buildPlatform then libcCross else null; + + isl = if !stdenv.isDarwin then isl_0_17 else null; + })); + + gcc-snapshot = lowPrio (wrapCC (callPackage ../development/compilers/gcc/snapshot { + inherit noSysDirs; + + # PGO seems to speed up compilation by gcc by ~10%, see #445 discussion + profiledCompiler = with stdenv; (!isDarwin && (isi686 || isx86_64)); + + libcCross = if stdenv.targetPlatform != stdenv.buildPlatform then libcCross else null; + + isl = isl_0_17; + })); + + gfortran = gfortran7; + + gfortran48 = wrapCC (gcc48.cc.override { + name = "gfortran"; + langFortran = true; + langCC = false; + langC = false; + profiledCompiler = false; + }); + + gfortran49 = wrapCC (gcc49.cc.override { + name = "gfortran"; + langFortran = true; + langCC = false; + langC = false; + profiledCompiler = false; + }); + + gfortran5 = wrapCC (gcc5.cc.override { + name = "gfortran"; + langFortran = true; + langCC = false; + langC = false; + profiledCompiler = false; + }); + + gfortran6 = wrapCC (gcc6.cc.override { + name = "gfortran"; + langFortran = true; + langCC = false; + langC = false; + profiledCompiler = false; + }); + + gfortran7 = wrapCC (gcc7.cc.override { + name = "gfortran"; + langFortran = true; + langCC = false; + langC = false; + profiledCompiler = false; + }); + + gcj = gcj6; + gcj6 = wrapCC (gcc6.cc.override { + name = "gcj"; + langJava = true; + langFortran = false; + langCC = false; + langC = false; + profiledCompiler = false; + inherit zip unzip zlib boehmgc gettext pkgconfig perl; + inherit (gnome2) libart_lgpl; + }); + + gnu-smalltalk = callPackage ../development/compilers/gnu-smalltalk { }; + + gccgo = gccgo6; + gccgo6 = wrapCC (gcc6.cc.override { + name = "gccgo6"; + langCC = true; #required for go. + langC = true; + langGo = true; + profiledCompiler = false; + }); + + gcl = callPackage ../development/compilers/gcl { + gmp = gmp4; + }; + + gcl_2_6_13_pre = callPackage ../development/compilers/gcl/2.6.13-pre.nix { }; + + gcc-arm-embedded-4_7 = pkgsi686Linux.callPackage ../development/compilers/gcc-arm-embedded { + version = "4.7-2013q3-20130916"; + releaseType = "update"; + sha256 = "1bd9bi9q80xn2rpy0rn1vvj70rh15kb7dmah0qs4q2rv78fqj40d"; + ncurses = pkgsi686Linux.ncurses5; + }; + gcc-arm-embedded-4_8 = pkgsi686Linux.callPackage ../development/compilers/gcc-arm-embedded { + version = "4.8-2014q1-20140314"; + releaseType = "update"; + sha256 = "ce92859550819d4a3d1a6e2672ea64882b30afa2c08cf67fa8e1d93788c2c577"; + ncurses = pkgsi686Linux.ncurses5; + }; + gcc-arm-embedded-4_9 = pkgsi686Linux.callPackage ../development/compilers/gcc-arm-embedded { + version = "4.9-2015q1-20150306"; + releaseType = "update"; + sha256 = "c5e0025b065750bbd76b5357b4fc8606d88afbac9ff55b8a82927b4b96178154"; + ncurses = pkgsi686Linux.ncurses5; + }; + gcc-arm-embedded-5 = pkgs.pkgsi686Linux.callPackage ../development/compilers/gcc-arm-embedded { + dirName = "5.0"; + subdirName = "5-2016-q2-update"; + version = "5.4-2016q2-20160622"; + releaseType = "update"; + sha256 = "1r0rqbnw7rf94f5bsa3gi8bick4xb7qnp1dkvdjfbvqjvysvc44r"; + ncurses = pkgsi686Linux.ncurses5; + }; + gcc-arm-embedded-6 = callPackage ../development/compilers/gcc-arm-embedded/6 {}; + gcc-arm-embedded-7 = callPackage ../development/compilers/gcc-arm-embedded/7 {}; + gcc-arm-embedded-8 = callPackage ../development/compilers/gcc-arm-embedded/8 {}; + gcc-arm-embedded = gcc-arm-embedded-8; + + gforth = callPackage ../development/compilers/gforth {}; + + gtk-server = callPackage ../development/interpreters/gtk-server {}; + + # Haskell and GHC + + haskell = callPackage ./haskell-packages.nix { }; + + haskellPackages = dontRecurseIntoAttrs haskell.packages.ghc865; + + inherit (haskellPackages) ghc; + + cabal-install = haskell.lib.justStaticExecutables haskellPackages.cabal-install; + + stack = haskell.lib.justStaticExecutables haskellPackages.stack; + hlint = haskell.lib.justStaticExecutables haskellPackages.hlint; + stylish-cabal = haskell.lib.justStaticExecutables haskellPackages.stylish-cabal; + + all-cabal-hashes = callPackage ../data/misc/hackage { }; + + purescript = callPackage ../development/compilers/purescript/purescript { }; + + psc-package = haskell.lib.justStaticExecutables + (haskellPackages.callPackage ../development/compilers/purescript/psc-package { }); + + tamarin-prover = + (haskellPackages.callPackage ../applications/science/logic/tamarin-prover { + # NOTE: do not use the haskell packages 'graphviz' and 'maude' + inherit maude which; + graphviz = graphviz-nox; + }); + + inherit (ocaml-ng.ocamlPackages_4_05.haxe) haxe_3_2 haxe_3_4; + haxe = haxe_3_4; + haxePackages = recurseIntoAttrs (callPackage ./haxe-packages.nix { }); + inherit (haxePackages) hxcpp; + + hhvm = callPackage ../development/compilers/hhvm { }; + + hop = callPackage ../development/compilers/hop { }; + + falcon = callPackage ../development/interpreters/falcon { }; + + fsharp = callPackage ../development/compilers/fsharp { }; + + fsharp41 = callPackage ../development/compilers/fsharp41 { mono = mono4; }; + + fstar = callPackage ../development/compilers/fstar { }; + + pyre = callPackage ../development/tools/pyre { }; + + dotnetPackages = recurseIntoAttrs (callPackage ./dotnet-packages.nix {}); + + glslang = callPackage ../development/compilers/glslang { + spirv-tools = spirv-tools.overrideAttrs (_: { + src = fetchFromGitHub { + owner = "KhronosGroup"; + repo = "SPIRV-Tools"; + rev = "117a1fd11f11e9bef9faa563c3d5156cc6ab529c"; + sha256 = "1w5hb6sgy71g279wsghixxc75r7rsm7wki011mpz039q66827sym"; + }; + }); + spirv-headers = spirv-tools.overrideAttrs (_: { + src = fetchFromGitHub { + owner = "KhronosGroup"; + repo = "SPIRV-Tools"; + rev = "79b6681aadcb53c27d1052e5f8a0e82a981dbf2f"; + sha256 = "0flng2rdmc4ndq3j71h6wk1ibcjvhjrg2rzd6rv445vcsf0jh2pj"; + }; + }); + }; + + go_bootstrap = if stdenv.isAarch64 then + srcOnly { + name = "go-1.8-linux-arm64-bootstrap"; + src = fetchurl { + url = "https://cache.xor.us/go-1.8-linux-arm64-bootstrap.tar.xz"; + sha256 = "0sk6g03x9gbxk2k1djnrgy8rzw1zc5f6ssw0hbxk6kjr85lpmld6"; + }; + } + else + callPackage ../development/compilers/go/1.4.nix { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + go_1_10 = callPackage ../development/compilers/go/1.10.nix { + inherit (darwin.apple_sdk.frameworks) Security Foundation; + }; + + go_1_11 = callPackage ../development/compilers/go/1.11.nix { + inherit (darwin.apple_sdk.frameworks) Security Foundation; + }; + + go_1_12 = callPackage ../development/compilers/go/1.12.nix { + inherit (darwin.apple_sdk.frameworks) Security Foundation; + }; + + go = go_1_12; + + go-repo-root = callPackage ../development/tools/go-repo-root { }; + + go-junit-report = callPackage ../development/tools/go-junit-report { }; + + gogetdoc = callPackage ../development/tools/gogetdoc { }; + + gometalinter = callPackage ../development/tools/gometalinter { }; + + gox = callPackage ../development/tools/gox { }; + + gprolog = callPackage ../development/compilers/gprolog { }; + + gwt240 = callPackage ../development/compilers/gwt/2.4.0.nix { }; + + idrisPackages = dontRecurseIntoAttrs (callPackage ../development/idris-modules { + idris-no-deps = haskellPackages.idris; + }); + + idris = idrisPackages.with-packages [ idrisPackages.base ] ; + + intercal = callPackage ../development/compilers/intercal { }; + + irony-server = callPackage ../development/tools/irony-server { + # The repository of irony to use -- must match the version of the employed emacs + # package. Wishing we could merge it into one irony package, to avoid this issue, + # but its emacs-side expression is autogenerated, and we can't hook into it (other + # than peek into its version). + inherit (emacsPackagesNg.melpaStablePackages) irony; + }; + + hugs = callPackage ../development/interpreters/hugs { }; + + bootjdk = callPackage ../development/compilers/openjdk/bootstrap.nix { version = "10"; }; + + openjfx11 = + if stdenv.isDarwin then + null + else + callPackage ../development/compilers/openjdk/openjfx/11.nix { + openjdk = openjdk11; + }; + + /* legacy jdk for use as needed by older apps */ + openjdk8 = + if stdenv.isDarwin then + callPackage ../development/compilers/openjdk/darwin/8.nix { } + else + callPackage ../development/compilers/openjdk/8.nix { + bootjdk = bootjdk.override { version = "8"; }; + inherit (gnome2) GConf gnome_vfs; + }; + + /* currently maintained LTS JDK */ + openjdk11 = + if stdenv.isDarwin then + callPackage ../development/compilers/openjdk/darwin/11.nix { } + else + callPackage ../development/compilers/openjdk/11.nix { + openjfx = openjfx11; + inherit (gnome2) GConf gnome_vfs; + }; + + openjfx12 = + if stdenv.isDarwin then + null + else + callPackage ../development/compilers/openjdk/openjfx/12.nix { + openjdk = openjdk12; + bootjdk = openjdk11; + }; + + /* current JDK */ + openjdk12 = + if stdenv.isDarwin then + callPackage ../development/compilers/openjdk/darwin/default.nix { } + else + callPackage ../development/compilers/openjdk/default.nix { + openjfx = openjfx12; + inherit (gnome2) GConf gnome_vfs; + bootjdk = openjdk11; + }; + + openjdk = openjdk8; + + jdk8 = if stdenv.isAarch32 || stdenv.isAarch64 then oraclejdk8 else openjdk8 // { outputs = [ "out" ]; }; + jre8 = if stdenv.isAarch32 || stdenv.isAarch64 then oraclejre8 else lib.setName "openjre-${lib.getVersion pkgs.openjdk8.jre}" + (lib.addMetaAttrs { outputsToInstall = [ "jre" ]; } + (openjdk8.jre // { outputs = [ "jre" ]; })); + jre8_headless = + if stdenv.isAarch32 || stdenv.isAarch64 then + oraclejre8 + else if stdenv.isDarwin then + jre8 + else + lib.setName "openjre-${lib.getVersion pkgs.openjdk8.jre}-headless" + (lib.addMetaAttrs { outputsToInstall = [ "jre" ]; } + ((openjdk8.override { minimal = true; }).jre // { outputs = [ "jre" ]; })); + + jdk11 = openjdk11 // { outputs = [ "out" ]; }; + jdk11_headless = + if stdenv.isDarwin then + jdk11 + else + lib.setName "openjdk-${lib.getVersion pkgs.openjdk11}-headless" + (lib.addMetaAttrs {} + ((openjdk11.override { minimal = true; }) // {})); + + jdk12 = openjdk12 // { outputs = [ "out" ]; }; + jdk12_headless = + if stdenv.isDarwin then + jdk12 + else + lib.setName "openjdk-${lib.getVersion pkgs.openjdk12}-headless" + (lib.addMetaAttrs {} + ((openjdk12.override { minimal = true; }) // {})); + + jdk = jdk8; + jre = if stdenv.isAarch32 || stdenv.isAarch64 then adoptopenjdk-jre-bin else jre8; + jre_headless = jre8_headless; + + inherit (callPackages ../development/compilers/graalvm { }) mx jvmci8 graalvm8; + + graalvm8-ee = callPackage ../development/compilers/graalvm/enterprise-edition.nix { }; + + openshot-qt = libsForQt5.callPackage ../applications/video/openshot-qt { }; + + openspin = callPackage ../development/compilers/openspin { }; + + oraclejdk = pkgs.jdkdistro true false; + + oraclejdk8 = pkgs.oraclejdk8distro true false; + + oraclejdk8psu = pkgs.oraclejdk8psu_distro true false; + + oraclejre = lowPrio (pkgs.jdkdistro false false); + + oraclejre8 = lowPrio (pkgs.oraclejdk8distro false false); + + oraclejre8psu = lowPrio (pkgs.oraclejdk8psu_distro false false); + + jrePlugin = jre8Plugin; + + jre8Plugin = lowPrio (pkgs.oraclejdk8distro false true); + + jdkdistro = oraclejdk8distro; + + oraclejdk8distro = installjdk: pluginSupport: + (if pluginSupport then appendToName "with-plugin" else x: x) + (callPackage ../development/compilers/oraclejdk/jdk8cpu-linux.nix { + inherit installjdk pluginSupport; + }); + + oraclejdk8psu_distro = installjdk: pluginSupport: + (if pluginSupport then appendToName "with-plugin" else x: x) + (callPackage ../development/compilers/oraclejdk/jdk8psu-linux.nix { + inherit installjdk pluginSupport; + }); + + javacard-devkit = pkgsi686Linux.callPackage ../development/compilers/javacard-devkit { }; + + jikes = callPackage ../development/compilers/jikes { }; + + julia_07 = callPackage ../development/compilers/julia/0.7.nix { + gmp = gmp6; + openblas = openblasCompat; + inherit (darwin.apple_sdk.frameworks) CoreServices ApplicationServices; + }; + + julia_10 = callPackage ../development/compilers/julia/1.0.nix { + gmp = gmp6; + openblas = openblasCompat; + inherit (darwin.apple_sdk.frameworks) CoreServices ApplicationServices; + }; + + julia_11 = callPackage ../development/compilers/julia/1.1.nix { + gmp = gmp6; + openblas = openblasCompat; + inherit (darwin.apple_sdk.frameworks) CoreServices ApplicationServices; + }; + + julia_1 = julia_10; + julia = julia_1; + + jwasm = callPackage ../development/compilers/jwasm { }; + + kotlin = callPackage ../development/compilers/kotlin { }; + + lazarus = callPackage ../development/compilers/fpc/lazarus.nix { + fpc = fpc; + }; + + lessc = nodePackages.less; + + liquibase = callPackage ../development/tools/database/liquibase { }; + + lizardfs = callPackage ../tools/filesystems/lizardfs { }; + + lld = llvmPackages.lld; + lld_4 = llvmPackages_4.lld; + lld_5 = llvmPackages_5.lld; + lld_6 = llvmPackages_6.lld; + lld_7 = llvmPackages_7.lld; + lld_8 = llvmPackages_8.lld; + + lldb = llvmPackages.lldb; + lldb_4 = llvmPackages_4.lldb; + lldb_5 = llvmPackages_5.lldb; + lldb_6 = llvmPackages_6.lldb; + lldb_7 = llvmPackages_7.lldb; + lldb_8 = llvmPackages_8.lldb; + + llvm = llvmPackages.llvm; + llvm-manpages = llvmPackages.llvm-manpages; + + llvm_8 = llvmPackages_8.llvm; + llvm_7 = llvmPackages_7.llvm; + llvm_6 = llvmPackages_6.llvm; + llvm_5 = llvmPackages_5.llvm; + llvm_4 = llvmPackages_4.llvm; + llvm_39 = llvmPackages_39.llvm; + llvm_38 = llvmPackages_38.llvm; + llvm_35 = llvmPackages_35.llvm; + + llvmPackages = recurseIntoAttrs llvmPackages_7; + + llvmPackages_35 = callPackage ../development/compilers/llvm/3.5 ({ + isl = isl_0_14; + } // stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; + }); + + llvmPackages_38 = callPackage ../development/compilers/llvm/3.8 ({ + inherit (stdenvAdapters) overrideCC; + buildLlvmTools = buildPackages.llvmPackages_38.tools; + targetLlvmLibraries = targetPackages.llvmPackages_38.libraries; + } // stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; + }); + + llvmPackages_39 = callPackage ../development/compilers/llvm/3.9 ({ + inherit (stdenvAdapters) overrideCC; + buildLlvmTools = buildPackages.llvmPackages_39.tools; + targetLlvmLibraries = targetPackages.llvmPackages_39.libraries; + } // stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; + }); + + llvmPackages_4 = callPackage ../development/compilers/llvm/4 ({ + inherit (stdenvAdapters) overrideCC; + buildLlvmTools = buildPackages.llvmPackages_4.tools; + targetLlvmLibraries = targetPackages.llvmPackages_4.libraries; + } // stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; + }); + + llvmPackages_5 = callPackage ../development/compilers/llvm/5 ({ + inherit (stdenvAdapters) overrideCC; + buildLlvmTools = buildPackages.llvmPackages_5.tools; + targetLlvmLibraries = targetPackages.llvmPackages_5.libraries; + } // stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + }); + + llvmPackages_6 = callPackage ../development/compilers/llvm/6 ({ + inherit (stdenvAdapters) overrideCC; + buildLlvmTools = buildPackages.llvmPackages_6.tools; + targetLlvmLibraries = targetPackages.llvmPackages_6.libraries; + } // stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + }); + + llvmPackages_7 = callPackage ../development/compilers/llvm/7 ({ + inherit (stdenvAdapters) overrideCC; + buildLlvmTools = buildPackages.llvmPackages_7.tools; + targetLlvmLibraries = targetPackages.llvmPackages_7.libraries; + } // stdenv.lib.optionalAttrs (buildPackages.stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + }); + + llvmPackages_8 = callPackage ../development/compilers/llvm/8 ({ + inherit (stdenvAdapters) overrideCC; + buildLlvmTools = buildPackages.llvmPackages_8.tools; + targetLlvmLibraries = targetPackages.llvmPackages_8.libraries; + } // stdenv.lib.optionalAttrs (buildPackages.stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + }); + + llvmPackages_latest = llvmPackages_8; + + lorri = throw "lorri is not stable yet. Please go to https://github.com/target/lorri and follow the installation instructions there, for the time being."; + + manticore = callPackage ../development/compilers/manticore { }; + + mercury = callPackage ../development/compilers/mercury { }; + + microscheme = callPackage ../development/compilers/microscheme { }; + + mint = callPackage ../development/compilers/mint { }; + + mitscheme = callPackage ../development/compilers/mit-scheme { + texLive = texlive.combine { inherit (texlive) scheme-small; }; + texinfo = texinfo5; + xlibsWrapper = null; + }; + + mitschemeX11 = mitscheme.override { + texLive = texlive.combine { inherit (texlive) scheme-small; }; + texinfo = texinfo5; + enableX11 = true; + }; + + mkcl = callPackage ../development/compilers/mkcl {}; + + inherit (callPackage ../development/compilers/mlton {}) + mlton20130715 + mlton20180207Binary + mlton20180207 + mltonHEAD; + + mlton = mlton20180207; + + mono = mono5; + + mono4 = lowPrio (callPackage ../development/compilers/mono/4.nix { + inherit (darwin) libobjc; + inherit (darwin.apple_sdk.frameworks) Foundation; + }); + + mono5 = callPackage ../development/compilers/mono/5.nix { + inherit (darwin) libobjc; + inherit (darwin.apple_sdk.frameworks) Foundation; + }; + + monoDLLFixer = callPackage ../build-support/mono-dll-fixer { }; + + mosml = callPackage ../development/compilers/mosml { }; + + mozart-binary = callPackage ../development/compilers/mozart/binary.nix { }; + mozart = mozart-binary; + + nim = callPackage ../development/compilers/nim { }; + nrpl = callPackage ../development/tools/nrpl { }; + + neko = callPackage ../development/compilers/neko { }; + + nextpnr = libsForQt5.callPackage ../development/compilers/nextpnr { }; + + nasm = callPackage ../development/compilers/nasm { }; + + nvidia_cg_toolkit = callPackage ../development/compilers/nvidia-cg-toolkit { }; + + obliv-c = callPackage ../development/compilers/obliv-c { + ocamlPackages = ocaml-ng.ocamlPackages_4_05; + }; + + ocaml-ng = callPackage ./ocaml-packages.nix { }; + ocaml = ocamlPackages.ocaml; + + ocamlPackages = recurseIntoAttrs ocaml-ng.ocamlPackages; + + ocamlformat = callPackage ../development/tools/ocaml/ocamlformat { }; + + orc = callPackage ../development/compilers/orc { }; + + metaocaml_3_09 = callPackage ../development/compilers/ocaml/metaocaml-3.09.nix { }; + + ber_metaocaml = callPackage ../development/compilers/ocaml/ber-metaocaml.nix { }; + + ocaml_make = callPackage ../development/ocaml-modules/ocamlmake { }; + + ocaml-top = callPackage ../development/tools/ocaml/ocaml-top { }; + + ocsigen-i18n = callPackage ../development/tools/ocaml/ocsigen-i18n { }; + + opa = callPackage ../development/compilers/opa { + ocamlPackages = ocaml-ng.ocamlPackages_4_02; + }; + + opaline = callPackage ../development/tools/ocaml/opaline { }; + + opam = callPackage ../development/tools/ocaml/opam { }; + opam_1_2 = callPackage ../development/tools/ocaml/opam/1.2.2.nix { + inherit (ocaml-ng.ocamlPackages_4_05) ocaml; + }; + + pforth = callPackage ../development/compilers/pforth {}; + + picat = callPackage ../development/compilers/picat { + stdenv = gcc49Stdenv; + }; + + ponyc = callPackage ../development/compilers/ponyc { + llvm = llvm_7; + }; + + pony-stable = callPackage ../development/compilers/ponyc/pony-stable.nix { }; + + qbe = callPackage ../development/compilers/qbe { }; + + rgbds = callPackage ../development/compilers/rgbds { }; + + rtags = callPackage ../development/tools/rtags { + inherit (darwin) apple_sdk; + }; + + rust = callPackage ../development/compilers/rust { + inherit (darwin.apple_sdk.frameworks) CoreFoundation Security; + }; + rustPackages = rust.packages.stable; + inherit (rustPackages) cargo rustc rustPlatform; + inherit (rust) makeRustPlatform; + + buildRustCrate = callPackage ../build-support/rust/build-rust-crate { }; + buildRustCrateHelpers = callPackage ../build-support/rust/build-rust-crate/helpers.nix { }; + buildRustCrateTests = recurseIntoAttrs (callPackage ../build-support/rust/build-rust-crate/test { }).tests; + cratesIO = callPackage ../build-support/rust/crates-io.nix { }; + cargo-vendor = callPackage ../build-support/rust/cargo-vendor { }; + + cargo-web = callPackage ../development/tools/cargo-web { + inherit (darwin.apple_sdk.frameworks) CoreServices Security; + }; + + cargo-flamegraph = callPackage ../development/tools/cargo-flamegraph { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + carnix = (callPackage ../build-support/rust/carnix.nix { }).carnix { }; + + defaultCrateOverrides = callPackage ../build-support/rust/default-crate-overrides.nix { }; + + cargo-download = callPackage ../tools/package-management/cargo-download { }; + cargo-edit = callPackage ../tools/package-management/cargo-edit { }; + cargo-graph = callPackage ../tools/package-management/cargo-graph { }; + cargo-license = callPackage ../tools/package-management/cargo-license { }; + cargo-outdated = callPackage ../tools/package-management/cargo-outdated {}; + cargo-release = callPackage ../tools/package-management/cargo-release { + inherit (darwin.apple_sdk.frameworks) Security; + }; + cargo-tree = callPackage ../tools/package-management/cargo-tree { }; + cargo-update = callPackage ../tools/package-management/cargo-update { }; + + cargo-asm = callPackage ../development/tools/rust/cargo-asm { + inherit (darwin.apple_sdk.frameworks) Security; + }; + cargo-bloat = callPackage ../development/tools/rust/cargo-bloat { }; + cargo-expand = callPackage ../development/tools/rust/cargo-expand { }; + cargo-fuzz = callPackage ../development/tools/rust/cargo-fuzz { }; + cargo-inspect = callPackage ../development/tools/rust/cargo-inspect { }; + cargo-make = callPackage ../development/tools/rust/cargo-make { + inherit (darwin.apple_sdk.frameworks) Security; + }; + cargo-raze = callPackage ../development/tools/rust/cargo-raze { + inherit (darwin.apple_sdk.frameworks) Security; + }; + cargo-sweep = callPackage ../development/tools/rust/cargo-sweep { }; + cargo-xbuild = callPackage ../development/tools/rust/cargo-xbuild { }; + cargo-generate = callPackage ../development/tools/rust/cargo-generate { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + pyo3-pack = callPackage ../development/tools/rust/pyo3-pack { }; + rainicorn = callPackage ../development/tools/rust/rainicorn { }; + inherit (rustPackages) rls; + rustfmt = rustPackages.rustfmt; + rustracer = callPackage ../development/tools/rust/racer { + inherit (darwin.apple_sdk.frameworks) Security; + }; + rustracerd = callPackage ../development/tools/rust/racerd { }; + rust-bindgen = callPackage ../development/tools/rust/bindgen { }; + rust-cbindgen = callPackage ../development/tools/rust/cbindgen { + inherit (darwin.apple_sdk.frameworks) Security; + }; + rustup = callPackage ../development/tools/rust/rustup { + inherit (darwin.apple_sdk.frameworks) CoreServices Security; + }; + + sagittarius-scheme = callPackage ../development/compilers/sagittarius-scheme {}; + + sbclBootstrap = callPackage ../development/compilers/sbcl/bootstrap.nix {}; + sbcl = callPackage ../development/compilers/sbcl {}; + + scala_2_10 = callPackage ../development/compilers/scala/2.10.nix { }; + scala_2_11 = callPackage ../development/compilers/scala/2.11.nix { }; + scala_2_12 = callPackage ../development/compilers/scala/2.12.nix { jre = jre8; }; + scala_2_13 = callPackage ../development/compilers/scala/2.13.nix { jre = jre8; }; + scala = scala_2_13; + + scalafix = callPackage ../development/tools/scalafix { }; + scalafmt = callPackage ../development/tools/scalafmt { }; + + sdcc = callPackage ../development/compilers/sdcc { + gputils = null; + }; + + serialdv = callPackage ../development/libraries/serialdv { }; + + serpent = callPackage ../development/compilers/serpent { }; + + shmig = callPackage ../development/tools/database/shmig { }; + + smlnjBootstrap = callPackage ../development/compilers/smlnj/bootstrap.nix { }; + smlnj = if stdenv.isDarwin + then callPackage ../development/compilers/smlnj { } + else pkgsi686Linux.callPackage ../development/compilers/smlnj { }; + + solc = callPackage ../development/compilers/solc { }; + + souffle = callPackage ../development/compilers/souffle { }; + + sqldeveloper = callPackage ../development/tools/database/sqldeveloper { }; + + # sqldeveloper_18 needs JavaFX, which currently only is available inside the + # (non-free and net yet packaged for Darwin) OracleJDK + # we might be able to get rid of it, as soon as we have an OpenJDK with OpenJFX included + sqldeveloper_18 = callPackage ../development/tools/database/sqldeveloper/18.2.nix { + jdk = oraclejdk; + }; + + squeak = callPackage ../development/compilers/squeak { }; + + squirrel-sql = callPackage ../development/tools/database/squirrel-sql { + drivers = [ mssql_jdbc mysql_jdbc postgresql_jdbc ]; + }; + + stalin = callPackage ../development/compilers/stalin { }; + + metaBuildEnv = callPackage ../development/compilers/meta-environment/meta-build-env { }; + + svd2rust = callPackage ../development/tools/rust/svd2rust { }; + + swift = callPackage ../development/compilers/swift { }; + + swiProlog = callPackage ../development/compilers/swi-prolog { }; + + tbb = callPackage ../development/libraries/tbb { }; + + terra = callPackage ../development/compilers/terra { + llvmPackages = llvmPackages_6; + lua = lua5_1; + }; + + teyjus = callPackage ../development/compilers/teyjus ( + with ocaml-ng.ocamlPackages_4_02; { + inherit ocaml; + omake = omake_rc1; + }); + + thrust = callPackage ../development/tools/thrust { + gconf = pkgs.gnome2.GConf; + }; + + tinycc = callPackage ../development/compilers/tinycc { }; + + tinyscheme = callPackage ../development/interpreters/tinyscheme { + stdenv = gccStdenv; + }; + + inherit (ocaml-ng.ocamlPackages_4_02) trv; + + bupc = callPackage ../development/compilers/bupc { }; + + urn = callPackage ../development/compilers/urn { }; + + urweb = callPackage ../development/compilers/urweb { }; + + vlang = callPackage ../development/compilers/vlang { }; + + inherit (callPackage ../development/compilers/vala { }) + vala_0_36 + vala_0_38 + vala_0_40 + vala_0_42 + vala_0_44 + vala; + + valadoc = callPackage ../development/tools/valadoc { }; + + wcc = callPackage ../development/compilers/wcc { }; + + wla-dx = callPackage ../development/compilers/wla-dx { }; + + wrapCCWith = + { cc + , # This should be the only bintools runtime dep with this sort of logic. The + # Others should instead delegate to the next stage's choice with + # `targetPackages.stdenv.cc.bintools`. This one is different just to + # provide the default choice, avoiding infinite recursion. + bintools ? if stdenv.targetPlatform.isDarwin then darwin.binutils else binutils + , libc ? bintools.libc + , ... + } @ extraArgs: + callPackage ../build-support/cc-wrapper (let self = { + nativeTools = stdenv.targetPlatform == stdenv.hostPlatform && stdenv.cc.nativeTools or false; + nativeLibc = stdenv.targetPlatform == stdenv.hostPlatform && stdenv.cc.nativeLibc or false; + nativePrefix = stdenv.cc.nativePrefix or ""; + noLibc = !self.nativeLibc && (self.libc == null); + + isGNU = cc.isGNU or false; + isClang = cc.isClang or false; + + inherit cc bintools libc; + } // extraArgs; in self); + + wrapCC = cc: wrapCCWith { + inherit cc; + }; + + wrapBintoolsWith = + { bintools + , libc ? if stdenv.targetPlatform != stdenv.hostPlatform then libcCross else stdenv.cc.libc + , ... + } @ extraArgs: + callPackage ../build-support/bintools-wrapper (let self = { + nativeTools = stdenv.targetPlatform == stdenv.hostPlatform && stdenv.cc.nativeTools or false; + nativeLibc = stdenv.targetPlatform == stdenv.hostPlatform && stdenv.cc.nativeLibc or false; + nativePrefix = stdenv.cc.nativePrefix or ""; + + noLibc = (self.libc == null); + + inherit bintools libc; + } // extraArgs; in self); + + # prolog + yap = callPackage ../development/compilers/yap { }; + + yasm = callPackage ../development/compilers/yasm { }; + + yosys = callPackage ../development/compilers/yosys { }; + + z88dk = callPackage ../development/compilers/z88dk { }; + + zulu8 = callPackage ../development/compilers/zulu/8.nix { }; + zulu = callPackage ../development/compilers/zulu { }; + + ### DEVELOPMENT / INTERPRETERS + + acl2 = callPackage ../development/interpreters/acl2 { }; + + angelscript = callPackage ../development/interpreters/angelscript {}; + + angelscript_2_22 = callPackage ../development/interpreters/angelscript/2.22.nix {}; + + chibi = callPackage ../development/interpreters/chibi { }; + + ceptre = callPackage ../development/interpreters/ceptre { }; + + clips = callPackage ../development/interpreters/clips { }; + + clisp = callPackage ../development/interpreters/clisp { }; + clisp-tip = callPackage ../development/interpreters/clisp/hg.nix { }; + + clojure = callPackage ../development/interpreters/clojure { }; + + clooj = callPackage ../development/interpreters/clojure/clooj.nix { }; + + dhall = callPackage ../development/interpreters/dhall { }; + + dhall-nix = haskell.lib.justStaticExecutables haskellPackages.dhall-nix; + + dhall-bash = haskell.lib.justStaticExecutables haskellPackages.dhall-bash; + + dhall-json = haskell.lib.justStaticExecutables haskellPackages.dhall-json; + + dhall-text = haskell.lib.justStaticExecutables haskellPackages.dhall-text; + + dhallPackages = import ../development/dhall-modules { inherit pkgs; }; + + duktape = callPackage ../development/interpreters/duktape { }; + + evcxr = callPackage ../development/interpreters/evcxr { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + beam = callPackage ./beam-packages.nix { }; + + inherit (beam.interpreters) + erlang erlangR18 erlangR19 erlangR20 erlangR21 erlangR22 + erlang_odbc erlang_javac erlang_odbc_javac erlang_nox erlang_basho_R16B02 + elixir elixir_1_9 elixir_1_8 elixir_1_7 elixir_1_6 elixir_1_5 + lfe lfe_1_2; + + inherit (beam.packages.erlang) + rebar rebar3-open rebar3 + hexRegistrySnapshot fetchHex beamPackages + hex2nix relxExe; + + inherit (beam.packages.erlangR19) cuter; + + groovy = callPackage ../development/interpreters/groovy { }; + + guile_1_8 = callPackage ../development/interpreters/guile/1.8.nix { }; + + # Needed for autogen + guile_2_0 = callPackage ../development/interpreters/guile/2.0.nix { }; + + guile_2_2 = callPackage ../development/interpreters/guile { }; + + guile = guile_2_2; + + inherit (callPackages ../applications/networking/cluster/hadoop { }) + hadoop_2_7 + hadoop_2_8 + hadoop_2_9 + hadoop_3_0 + hadoop_3_1; + hadoop = hadoop_2_7; + + io = callPackage ../development/interpreters/io { }; + + j = callPackage ../development/interpreters/j {}; + + janet = callPackage ../development/interpreters/janet {}; + + jimtcl = callPackage ../development/interpreters/jimtcl {}; + + jmeter = callPackage ../applications/networking/jmeter {}; + + joker = callPackage ../development/interpreters/joker {}; + + davmail = callPackage ../applications/networking/davmail {}; + + kanif = callPackage ../applications/networking/cluster/kanif { }; + + lumo = callPackage ../development/interpreters/clojurescript/lumo { + nodejs = nodejs-10_x; + }; + + lxappearance = callPackage ../desktops/lxde/core/lxappearance { + gtk2 = gtk2-x11; + }; + + lxappearance-gtk3 = lxappearance.override { + withGtk3 = true; + }; + + lxmenu-data = callPackage ../desktops/lxde/core/lxmenu-data.nix { }; + + lxpanel = callPackage ../desktops/lxde/core/lxpanel { + gtk2 = gtk2-x11; + }; + + lxtask = callPackage ../desktops/lxde/core/lxtask { }; + + lxrandr = callPackage ../desktops/lxde/core/lxrandr { }; + + kona = callPackage ../development/interpreters/kona {}; + + lolcode = callPackage ../development/interpreters/lolcode { }; + + love_0_7 = callPackage ../development/interpreters/love/0.7.nix { lua=lua5_1; }; + love_0_8 = callPackage ../development/interpreters/love/0.8.nix { lua=lua5_1; }; + love_0_9 = callPackage ../development/interpreters/love/0.9.nix { }; + love_0_10 = callPackage ../development/interpreters/love/0.10.nix { }; + love_11 = callPackage ../development/interpreters/love/11.1.nix { }; + love = love_0_10; + + wabt = callPackage ../development/tools/wabt { }; + + ### LUA interpreters + luaInterpreters = callPackage ./../development/interpreters/lua-5 {}; + inherit (luaInterpreters) lua5_1 lua5_2 lua5_2_compat lua5_3 lua5_3_compat luajit_2_1 luajit_2_0; + + lua5 = lua5_2_compat; + lua = lua5; + + lua51Packages = recurseIntoAttrs lua5_1.pkgs; + lua52Packages = recurseIntoAttrs lua5_2.pkgs; + lua53Packages = recurseIntoAttrs lua5_3.pkgs; + luajitPackages = recurseIntoAttrs luajit.pkgs; + + luaPackages = lua52Packages; + + luajit = luajit_2_1; + + luarocks = luaPackages.luarocks; + luarocks-nix = luaPackages.luarocks-nix; + + toluapp = callPackage ../development/tools/toluapp { + lua = lua5_1; # doesn't work with any other :( + }; + + ### END OF LUA + + lush2 = callPackage ../development/interpreters/lush {}; + + maude = callPackage ../development/interpreters/maude { + stdenv = if stdenv.cc.isClang then llvmPackages_5.stdenv else stdenv; + }; + + me_cleaner = pythonPackages.callPackage ../tools/misc/me_cleaner { }; + + mesos = callPackage ../applications/networking/cluster/mesos { + sasl = cyrus_sasl; + inherit (pythonPackages) python boto setuptools wrapPython; + pythonProtobuf = pythonPackages.protobuf.override { protobuf = protobuf3_6; }; + perf = linuxPackages.perf; + }; + + mesos-dns = callPackage ../servers/mesos-dns { }; + + metamath = callPackage ../development/interpreters/metamath { }; + + mujs = callPackage ../development/interpreters/mujs { }; + + nix-exec = callPackage ../development/interpreters/nix-exec { + git = gitMinimal; + }; + + inherit ( + let + defaultOctaveOptions = { + qt = null; + ghostscript = null; + graphicsmagick = null; + llvm = null; + hdf5 = null; + glpk = null; + suitesparse = null; + jdk = null; + openblas = if stdenv.isDarwin then openblasCompat else openblas; + }; + + hgOctaveOptions = + (removeAttrs defaultOctaveOptions ["ghostscript"]) // { + overridePlatforms = stdenv.lib.platforms.none; + }; + in { + octave = callPackage ../development/interpreters/octave defaultOctaveOptions; + octaveHg = lowPrio (callPackage ../development/interpreters/octave/hg.nix hgOctaveOptions); + }) octave octaveHg; + + octaveFull = (lowPrio (octave.override { + qt = qt4; + overridePlatforms = ["x86_64-linux" "x86_64-darwin"]; + openblas = if stdenv.isDarwin then openblasCompat else openblas; + })); + + ocropus = callPackage ../applications/misc/ocropus { }; + + pachyderm = callPackage ../applications/networking/cluster/pachyderm { }; + + php = php73; + phpPackages = php73Packages; + + php72Packages = recurseIntoAttrs (callPackage ./php-packages.nix { + php = php72; + }); + + php73Packages = recurseIntoAttrs (callPackage ./php-packages.nix { + php = php73; + }); + + phpPackages-unit = php72Packages-unit; + + php72Packages-unit = recurseIntoAttrs (callPackage ./php-packages.nix { + php = php72-unit; + }); + + php73Packages-unit = recurseIntoAttrs (callPackage ./php-packages.nix { + php = php73-unit; + }); + + inherit (callPackages ../development/interpreters/php { + stdenv = if stdenv.cc.isClang then llvmPackages_6.stdenv else stdenv; + }) + php72 + php73; + + php-embed = php73-embed; + + php72-embed = php72.override { + config.php.embed = true; + config.php.apxs2 = false; + }; + + php73-embed = php73.override { + config.php.embed = true; + config.php.apxs2 = false; + }; + + php-unit = php73-unit; + + php72-unit = php72.override { + config.php.embed = true; + config.php.apxs2 = false; + config.php.systemd = false; + config.php.phpdbg = false; + config.php.cgi = false; + config.php.fpm = false; + }; + + php73-unit = php73.override { + config.php.embed = true; + config.php.apxs2 = false; + config.php.systemd = false; + config.php.phpdbg = false; + config.php.cgi = false; + config.php.fpm = false; + }; + + picoc = callPackage ../development/interpreters/picoc {}; + + picolisp = callPackage ../development/interpreters/picolisp {}; + + polyml = callPackage ../development/compilers/polyml { }; + polyml56 = callPackage ../development/compilers/polyml/5.6.nix { }; + polyml57 = callPackage ../development/compilers/polyml/5.7.nix { }; + + pure = callPackage ../development/interpreters/pure { + llvm = llvm_35; + }; + purePackages = recurseIntoAttrs (callPackage ./pure-packages.nix {}); + + # Python interpreters. All standard library modules are included except for tkinter, which is + # available as `pythonPackages.tkinter` and can be used as any other Python package. + # When switching these sets, please update docs at ../../doc/languages-frameworks/python.md + python = python2; + python2 = python27; + python3 = python37; + pypy = pypy2; + pypy2 = pypy27; + pypy3 = pypy36; + + # Python interpreter that is build with all modules, including tkinter. + # These are for compatibility and should not be used inside Nixpkgs. + pythonFull = python.override{x11Support=true;}; + python2Full = python2.override{x11Support=true;}; + python27Full = python27.override{x11Support=true;}; + python3Full = python3.override{x11Support=true;}; + python35Full = python35.override{x11Support=true;}; + python36Full = python36.override{x11Support=true;}; + python37Full = python37.override{x11Support=true;}; + python38Full = python38.override{x11Support=true;}; + + # pythonPackages further below, but assigned here because they need to be in sync + pythonPackages = python.pkgs; + python2Packages = python2.pkgs; + python3Packages = python3.pkgs; + + pythonInterpreters = callPackage ./../development/interpreters/python {}; + inherit (pythonInterpreters) python27 python35 python36 python37 python38 python3Minimal pypy27 pypy36; + + # Python package sets. + python27Packages = lib.hiPrioSet (recurseIntoAttrs python27.pkgs); + python35Packages = python35.pkgs; + python36Packages = python36.pkgs; + python37Packages = recurseIntoAttrs python37.pkgs; + python38Packages = python38.pkgs; + pypyPackages = pypy.pkgs; + pypy2Packages = pypy2.pkgs; + pypy27Packages = pypy27.pkgs; + pypy3Packages = pypy3.pkgs; + + update-python-libraries = callPackage ../development/interpreters/python/update-python-libraries { }; + + # Should eventually be moved inside Python interpreters. + python-setup-hook = callPackage ../development/interpreters/python/setup-hook.nix { }; + + python2nix = callPackage ../tools/package-management/python2nix { }; + + pythonDocs = recurseIntoAttrs (callPackage ../development/interpreters/python/cpython/docs {}); + + pypi2nix = callPackage ../development/tools/pypi2nix { + pythonPackages = python3Packages; + }; + + setupcfg2nix = python3Packages.callPackage ../development/tools/setupcfg2nix {}; + + # These pyside tools do not provide any Python modules and are meant to be here. + # See ../development/python-modules/pyside/default.nix for details. + pysideApiextractor = callPackage ../development/python-modules/pyside/apiextractor.nix { }; + pysideGeneratorrunner = callPackage ../development/python-modules/pyside/generatorrunner.nix { }; + + svg2tikz = python27Packages.svg2tikz; + + pew = callPackage ../development/tools/pew {}; + poetry = with python3Packages; toPythonApplication poetry; + pipenv = python3Packages.callPackage ../development/tools/pipenv {}; + + pipewire = callPackage ../development/libraries/pipewire {}; + + pyrex = pyrex095; + + pyrex095 = callPackage ../development/interpreters/pyrex/0.9.5.nix { }; + + pyrex096 = callPackage ../development/interpreters/pyrex/0.9.6.nix { }; + + racket = callPackage ../development/interpreters/racket { + # racket 6.11 doesn't build with gcc6 + recent glibc: + # https://github.com/racket/racket/pull/1886 + # https://github.com/NixOS/nixpkgs/pull/31017#issuecomment-343574769 + stdenv = if stdenv.isDarwin then stdenv else gcc7Stdenv; + inherit (darwin.apple_sdk.frameworks) CoreFoundation; + }; + racket-minimal = callPackage ../development/interpreters/racket/minimal.nix { }; + + rakudo = callPackage ../development/interpreters/rakudo { + inherit (darwin.apple_sdk.frameworks) CoreServices ApplicationServices; + }; + + rascal = callPackage ../development/interpreters/rascal { }; + + red = callPackage ../development/interpreters/red { }; + + regextester = callPackage ../applications/misc/regextester { }; + + regina = callPackage ../development/interpreters/regina { }; + + inherit (ocamlPackages) reason; + + renpy = callPackage ../development/interpreters/renpy { }; + + pixie = callPackage ../development/interpreters/pixie { }; + dust = callPackage ../development/interpreters/pixie/dust.nix { }; + + buildRubyGem = callPackage ../development/ruby-modules/gem { }; + defaultGemConfig = callPackage ../development/ruby-modules/gem-config { }; + bundix = callPackage ../development/ruby-modules/bundix { }; + bundler = callPackage ../development/ruby-modules/bundler { }; + bundlerEnv = callPackage ../development/ruby-modules/bundler-env { }; + bundlerApp = callPackage ../development/ruby-modules/bundler-app { }; + bundlerUpdateScript = callPackage ../development/ruby-modules/bundler-update-script { }; + + bundler-audit = callPackage ../tools/security/bundler-audit { }; + + solargraph = callPackage ../development/ruby-modules/solargraph { }; + + inherit (callPackage ../development/interpreters/ruby { + inherit (darwin) libiconv libobjc libunwind; + inherit (darwin.apple_sdk.frameworks) Foundation; + }) + ruby_2_3 + ruby_2_4 + ruby_2_5 + ruby_2_6; + + ruby = ruby_2_5; + + mruby = callPackage ../development/compilers/mruby { }; + + scsh = callPackage ../development/interpreters/scsh { }; + + scheme48 = callPackage ../development/interpreters/scheme48 { }; + + self = pkgsi686Linux.callPackage ../development/interpreters/self { }; + + spark = spark_24; + spark_24 = callPackage ../applications/networking/cluster/spark { version = "2.4.3"; }; + + spidermonkey_1_8_5 = callPackage ../development/interpreters/spidermonkey/1.8.5.nix { }; + spidermonkey_38 = callPackage ../development/interpreters/spidermonkey/38.nix ({ + inherit (darwin) libobjc; + } // (stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + })); + spidermonkey_52 = callPackage ../development/interpreters/spidermonkey/52.nix { }; + spidermonkey_60 = callPackage ../development/interpreters/spidermonkey/60.nix { }; + spidermonkey = spidermonkey_38; + + ssm-agent = callPackage ../applications/networking/cluster/ssm-agent { }; + + supercollider = libsForQt5.callPackage ../development/interpreters/supercollider { + fftw = fftwSinglePrec; + }; + + supercollider_scel = supercollider.override { useSCEL = true; }; + + taktuk = callPackage ../applications/networking/cluster/taktuk { }; + + tcl = tcl-8_6; + tcl-8_5 = callPackage ../development/interpreters/tcl/8.5.nix { }; + tcl-8_6 = callPackage ../development/interpreters/tcl/8.6.nix { }; + + proglodyte-wasm = callPackage ../development/interpreters/proglodyte-wasm { }; + + wasm-gc = callPackage ../development/interpreters/wasm-gc { }; + + + ### DEVELOPMENT / MISC + + amdadlsdk = callPackage ../development/misc/amdadl-sdk { }; + + amdappsdk26 = amdappsdk.override { + version = "2.6"; + }; + + amdappsdk27 = amdappsdk.override { + version = "2.7"; + }; + + amdappsdk28 = amdappsdk.override { + version = "2.8"; + }; + + amdappsdk = callPackage ../development/misc/amdapp-sdk { }; + + amdappsdkFull = amdappsdk.override { + samples = true; + }; + + amtk = callPackage ../development/libraries/amtk { }; + + avrlibc = callPackage ../development/misc/avr/libc {}; + avrlibcCross = callPackage ../development/misc/avr/libc { + stdenv = crossLibcStdenv; + }; + + avr8burnomat = callPackage ../development/misc/avr8-burn-omat { }; + + betaflight = callPackage ../development/misc/stm32/betaflight { + gcc-arm-embedded = pkgsCross.arm-embedded.buildPackages.gcc; + binutils-arm-embedded = pkgsCross.arm-embedded.buildPackages.binutils; + }; + + sourceFromHead = callPackage ../build-support/source-from-head-fun.nix {}; + + jruby = callPackage ../development/interpreters/jruby { }; + + jython = callPackage ../development/interpreters/jython {}; + + gImageReader = callPackage ../applications/misc/gImageReader { }; + + guile-cairo = callPackage ../development/guile-modules/guile-cairo { }; + + guile-fibers = callPackage ../development/guile-modules/guile-fibers { }; + + guile-gnome = callPackage ../development/guile-modules/guile-gnome { + gconf = gnome2.GConf; + guile = guile_2_0; + inherit (gnome2) gnome_vfs libglade libgnome libgnomecanvas libgnomeui; + }; + + guile-lib = callPackage ../development/guile-modules/guile-lib { }; + + guile-ncurses = callPackage ../development/guile-modules/guile-ncurses { }; + + guile-opengl = callPackage ../development/guile-modules/guile-opengl { }; + + guile-reader = callPackage ../development/guile-modules/guile-reader { }; + + guile-sdl = callPackage ../development/guile-modules/guile-sdl { }; + + guile-sdl2 = callPackage ../development/guile-modules/guile-sdl2 { }; + + guile-xcb = callPackage ../development/guile-modules/guile-xcb { + guile = guile_2_0; + }; + + inav = callPackage ../development/misc/stm32/inav { + gcc-arm-embedded = pkgsCross.arm-embedded.buildPackages.gcc; + binutils-arm-embedded = pkgsCross.arm-embedded.buildPackages.binutils; + }; + + msp430GccSupport = callPackage ../development/misc/msp430/gcc-support.nix { }; + + msp430Newlib = callPackage ../development/misc/msp430/newlib.nix { }; + msp430NewlibCross = callPackage ../development/misc/msp430/newlib.nix { + inherit (buildPackages.xorg) lndir; + newlib = newlibCross; + }; + + mspdebug = callPackage ../development/misc/msp430/mspdebug.nix { }; + + pharo-vms = callPackage ../development/pharo/vm { }; + pharo = pharo-vms.multi-vm-wrapper; + pharo-cog32 = pharo-vms.cog32; + pharo-spur32 = pharo-vms.spur32; + pharo-spur64 = assert stdenv.is64bit; pharo-vms.spur64; + pharo-launcher = callPackage ../development/pharo/launcher { }; + + srandrd = callPackage ../tools/X11/srandrd { }; + + srecord = callPackage ../development/tools/misc/srecord { }; + + srelay = callPackage ../tools/networking/srelay { }; + + xidel = callPackage ../tools/text/xidel { }; + + + ### DEVELOPMENT / TOOLS + + abi-compliance-checker = callPackage ../development/tools/misc/abi-compliance-checker { }; + + abi-dumper = callPackage ../development/tools/misc/abi-dumper { }; + + adtool = callPackage ../tools/admin/adtool { }; + + inherit (callPackage ../development/tools/alloy { }) + alloy4 + alloy5 + alloy; + + augeas = callPackage ../tools/system/augeas { }; + + inherit (callPackage ../tools/admin/ansible { }) + ansible + ansible_2_6 + ansible_2_7; + + ansible-lint = with python3.pkgs; toPythonApplication ansible-lint; + + antlr = callPackage ../development/tools/parsing/antlr/2.7.7.nix { }; + + antlr3_4 = callPackage ../development/tools/parsing/antlr/3.4.nix { }; + antlr3_5 = callPackage ../development/tools/parsing/antlr/3.5.nix { }; + antlr3 = antlr3_5; + + antlr4_7 = callPackage ../development/tools/parsing/antlr/4.7.nix { }; + antlr4 = antlr4_7; + + apacheAnt = callPackage ../development/tools/build-managers/apache-ant { }; + apacheAnt_1_9 = callPackage ../development/tools/build-managers/apache-ant/1.9.nix { }; + ant = apacheAnt; + + apacheKafka = apacheKafka_2_2; + apacheKafka_0_9 = callPackage ../servers/apache-kafka { majorVersion = "0.9"; }; + apacheKafka_0_10 = callPackage ../servers/apache-kafka { majorVersion = "0.10"; }; + apacheKafka_0_11 = callPackage ../servers/apache-kafka { majorVersion = "0.11"; }; + apacheKafka_1_0 = callPackage ../servers/apache-kafka { majorVersion = "1.0"; }; + apacheKafka_1_1 = callPackage ../servers/apache-kafka { majorVersion = "1.1"; }; + apacheKafka_2_0 = callPackage ../servers/apache-kafka { majorVersion = "2.0"; }; + apacheKafka_2_1 = callPackage ../servers/apache-kafka { majorVersion = "2.1"; }; + apacheKafka_2_2 = callPackage ../servers/apache-kafka { majorVersion = "2.2"; }; + + kt = callPackage ../tools/misc/kt {}; + + arpa2cm = callPackage ../development/tools/build-managers/arpa2cm { }; + + asn2quickder = python2Packages.callPackage ../development/tools/asn2quickder {}; + + astyle = callPackage ../development/tools/misc/astyle { }; + + awf = callPackage ../development/tools/misc/awf { }; + + electron_6 = callPackage ../development/tools/electron/6.x.nix { }; + + electron_5 = callPackage ../development/tools/electron/5.x.nix { }; + + electron_4 = callPackage ../development/tools/electron { }; + + electron_3 = callPackage ../development/tools/electron/3.x.nix { }; + electron = electron_4; + + autobuild = callPackage ../development/tools/misc/autobuild { }; + + autoconf = callPackage ../development/tools/misc/autoconf { }; + + autoconf-archive = callPackage ../development/tools/misc/autoconf-archive { }; + + autoconf213 = callPackage ../development/tools/misc/autoconf/2.13.nix { }; + autoconf264 = callPackage ../development/tools/misc/autoconf/2.64.nix { }; + + autocutsel = callPackage ../tools/X11/autocutsel{ }; + + automake = automake116x; + + automake111x = callPackage ../development/tools/misc/automake/automake-1.11.x.nix { }; + + automake115x = callPackage ../development/tools/misc/automake/automake-1.15.x.nix { }; + + automake116x = callPackage ../development/tools/misc/automake/automake-1.16.x.nix { }; + + automoc4 = callPackage ../development/tools/misc/automoc4 { }; + + avrdude = callPackage ../development/tools/misc/avrdude { }; + + avarice = callPackage ../development/tools/misc/avarice { + gcc = gcc49; + }; + + babeltrace = callPackage ../development/tools/misc/babeltrace { }; + + bam = callPackage ../development/tools/build-managers/bam {}; + + bazel_0_4 = callPackage ../development/tools/build-managers/bazel/0.4.nix { + stdenv = if stdenv.cc.isClang then llvmPackages_6.stdenv else stdenv; + }; + bazel = callPackage ../development/tools/build-managers/bazel { + inherit (darwin) cctools; + inherit (darwin.apple_sdk.frameworks) CoreFoundation CoreServices Foundation; + buildJdk = jdk8; + buildJdkName = "jdk8"; + runJdk = jdk11; + stdenv = if stdenv.cc.isClang then llvmPackages_6.stdenv else stdenv; + }; + + bazel-buildtools = callPackage ../development/tools/build-managers/bazel/buildtools { }; + buildifier = bazel-buildtools; + buildozer = bazel-buildtools; + unused_deps = bazel-buildtools; + + bazel-deps = callPackage ../development/tools/build-managers/bazel/bazel-deps { }; + + bazel-remote = callPackage ../development/tools/build-managers/bazel/bazel-remote { }; + + bazel-watcher = callPackage ../development/tools/bazel-watcher { }; + + bazelisk = callPackage ../development/tools/bazelisk { }; + + buildBazelPackage = callPackage ../build-support/build-bazel-package { }; + + bear = callPackage ../development/tools/build-managers/bear { }; + + bin_replace_string = callPackage ../development/tools/misc/bin_replace_string { }; + + binutils-unwrapped = callPackage ../development/tools/misc/binutils { + # FHS sys dirs presumably only have stuff for the build platform + noSysDirs = (stdenv.targetPlatform != stdenv.hostPlatform) || noSysDirs; + }; + binutils = wrapBintoolsWith { + bintools = binutils-unwrapped; + }; + binutils_nogold = lowPrio (wrapBintoolsWith { + bintools = binutils-unwrapped.override { + gold = false; + }; + }); + + bison2 = callPackage ../development/tools/parsing/bison/2.x.nix { }; + bison3 = callPackage ../development/tools/parsing/bison/3.x.nix { }; + bison = bison3; + yacc = bison; # TODO: move to aliases.nix + + blackmagic = callPackage ../development/tools/misc/blackmagic { }; + + bloaty = callPackage ../development/tools/bloaty { }; + + bloop = callPackage ../development/tools/build-managers/bloop { }; + + bossa = callPackage ../development/tools/misc/bossa { + wxGTK = wxGTK30; + }; + + buck = callPackage ../development/tools/build-managers/buck { }; + + buildkite-agent = buildkite-agent2; + buildkite-agent2 = callPackage ../development/tools/continuous-integration/buildkite-agent/2.x.nix { }; + buildkite-agent3 = callPackage ../development/tools/continuous-integration/buildkite-agent/3.x.nix { }; + + libbpf = callPackage ../os-specific/linux/libbpf { }; + + bpftool = callPackage ../os-specific/linux/bpftool { }; + + byacc = callPackage ../development/tools/parsing/byacc { }; + + cadre = callPackage ../development/tools/cadre { }; + + cask = callPackage ../development/tools/cask { }; + + casperjs = callPackage ../development/tools/casperjs { + inherit (texFunctions) fontsConf; + }; + + cbrowser = callPackage ../development/tools/misc/cbrowser { }; + + ccache = callPackage ../development/tools/misc/ccache { }; + + # Wrapper that works as gcc or g++ + # It can be used by setting in nixpkgs config like this, for example: + # replaceStdenv = { pkgs }: pkgs.ccacheStdenv; + # But if you build in chroot, you should have that path in chroot + # If instantiated directly, it will use $HOME/.ccache as the cache directory, + # i.e. /homeless-shelter/.ccache using the Nix daemon. + # You should specify a different directory using an override in + # packageOverrides to set extraConfig. + # + # Example using Nix daemon (i.e. multiuser Nix install or on NixOS): + # packageOverrides = pkgs: { + # ccacheWrapper = pkgs.ccacheWrapper.override { + # extraConfig = '' + # export CCACHE_COMPRESS=1 + # export CCACHE_DIR=/var/cache/ccache + # export CCACHE_UMASK=007 + # ''; + # }; + # You can use a different directory, but whichever directory you choose + # should be owned by user root, group nixbld with permissions 0770. + ccacheWrapper = makeOverridable ({ extraConfig ? "", unwrappedCC ? stdenv.cc.cc }: + wrapCC (ccache.links {inherit unwrappedCC extraConfig;})) {}; + ccacheStdenv = lowPrio (overrideCC stdenv buildPackages.ccacheWrapper); + + cccc = callPackage ../development/tools/analysis/cccc { }; + + cgdb = callPackage ../development/tools/misc/cgdb { }; + + cheat = callPackage ../applications/misc/cheat { }; + + chefdk = callPackage ../development/tools/chefdk { }; + + matter-compiler = callPackage ../development/compilers/matter-compiler {}; + + cfr = callPackage ../development/tools/java/cfr { }; + + checkstyle = callPackage ../development/tools/analysis/checkstyle { }; + + chromedriver = callPackage ../development/tools/selenium/chromedriver { gconf = gnome2.GConf; }; + + chrpath = callPackage ../development/tools/misc/chrpath { }; + + chruby = callPackage ../development/tools/misc/chruby { rubies = null; }; + + cide = callPackage ../development/tools/continuous-integration/cide { }; + + cl-launch = callPackage ../development/tools/misc/cl-launch {}; + + cloud-nuke = callPackage ../development/tools/cloud-nuke { }; + + cloudfoundry-cli = callPackage ../development/tools/cloudfoundry-cli { }; + + coan = callPackage ../development/tools/analysis/coan { }; + + compile-daemon = callPackage ../development/tools/compile-daemon { }; + + complexity = callPackage ../development/tools/misc/complexity { }; + + conan = callPackage ../development/tools/build-managers/conan { }; + + cookiecutter = pythonPackages.cookiecutter; + + corundum = callPackage ../development/tools/corundum { }; + + confluent-platform = callPackage ../servers/confluent-platform {}; + + ctags = callPackage ../development/tools/misc/ctags { }; + + ctagsWrapped = callPackage ../development/tools/misc/ctags/wrapped.nix {}; + + ctodo = callPackage ../applications/misc/ctodo { }; + + ctmg = callPackage ../tools/security/ctmg { }; + + cmake_2_8 = callPackage ../development/tools/build-managers/cmake/2.8.nix { }; + + cmake = libsForQt5.callPackage ../development/tools/build-managers/cmake { }; + + cmakeCurses = cmake.override { useNcurses = true; }; + + cmakeWithGui = cmakeCurses.override { withQt5 = true; }; + cmakeWithQt4Gui = cmakeCurses.override { useQt4 = true; }; + + # Does not actually depend on Qt 5 + inherit (kdeFrameworks) extra-cmake-modules kapidox kdoctools; + + coccinelle = callPackage ../development/tools/misc/coccinelle { + ocamlPackages = ocaml-ng.ocamlPackages_4_05; + }; + + cpptest = callPackage ../development/libraries/cpptest { }; + + cppi = callPackage ../development/tools/misc/cppi { }; + + cproto = callPackage ../development/tools/misc/cproto { }; + + cflow = callPackage ../development/tools/misc/cflow { }; + + cov-build = callPackage ../development/tools/analysis/cov-build {}; + + cppcheck = callPackage ../development/tools/analysis/cppcheck { }; + + cpplint = callPackage ../development/tools/analysis/cpplint { }; + + cquery = callPackage ../development/tools/misc/cquery { + # 7 is the default, but only on Linux, so keep this for now + llvmPackages = llvmPackages_7; + }; + + + ccls = callPackage ../development/tools/misc/ccls { + llvmPackages = llvmPackages_7; + stdenv = llvmPackages_7.stdenv; + }; + + credstash = with python3Packages; toPythonApplication credstash; + + creduce = callPackage ../development/tools/misc/creduce { + inherit (llvmPackages_7) llvm clang-unwrapped; + }; + + cscope = callPackage ../development/tools/misc/cscope { }; + + csmith = callPackage ../development/tools/misc/csmith { }; + + csslint = callPackage ../development/web/csslint { }; + + libcxx = llvmPackages.libcxx; + libcxxabi = llvmPackages.libcxxabi; + + librarian-puppet-go = callPackage ../development/tools/librarian-puppet-go { }; + + libgcc = callPackage ../development/libraries/gcc/libgcc { + stdenvNoLibs = gccStdenvNoLibs; # cannot be built with clang it seems + }; + + libstdcxx5 = callPackage ../development/libraries/gcc/libstdc++/5.nix { }; + + libsigrok = callPackage ../development/tools/libsigrok { }; + # old version: + libsigrok-0-3-0 = libsigrok.override { + version = "0.3.0"; + sha256 = "0l3h7zvn3w4c1b9dgvl3hirc4aj1csfkgbk87jkpl7bgl03nk4j3"; + }; + + libsigrokdecode = callPackage ../development/tools/libsigrokdecode { }; + + # special forks used for dsview + libsigrok4dsl = callPackage ../applications/science/electronics/dsview/libsigrok4dsl.nix { }; + libsigrokdecode4dsl = callPackage ../applications/science/electronics/dsview/libsigrokdecode4dsl.nix { }; + + cli11 = callPackage ../development/tools/misc/cli11 { }; + + dcadec = callPackage ../development/tools/dcadec { }; + + dejagnu = callPackage ../development/tools/misc/dejagnu { }; + + devd = callPackage ../development/tools/devd { }; + + devtodo = callPackage ../development/tools/devtodo { }; + + dfeet = callPackage ../development/tools/misc/d-feet { }; + + dfu-programmer = callPackage ../development/tools/misc/dfu-programmer { }; + + dfu-util = callPackage ../development/tools/misc/dfu-util { }; + + ddd = callPackage ../development/tools/misc/ddd { }; + + lattice-diamond = callPackage ../development/tools/lattice-diamond { }; + + distcc = callPackage ../development/tools/misc/distcc { + libiberty_static = libiberty.override { staticBuild = true; }; + }; + + # distccWrapper: wrapper that works as gcc or g++ + # It can be used by setting in nixpkgs config like this, for example: + # replaceStdenv = { pkgs }: pkgs.distccStdenv; + # But if you build in chroot, a default 'nix' will create + # a new net namespace, and won't have network access. + # You can use an override in packageOverrides to set extraConfig: + # packageOverrides = pkgs: { + # distccWrapper = pkgs.distccWrapper.override { + # extraConfig = '' + # DISTCC_HOSTS="myhost1 myhost2" + # ''; + # }; + # + distccWrapper = makeOverridable ({ extraConfig ? "" }: + wrapCC (distcc.links extraConfig)) {}; + distccStdenv = lowPrio (overrideCC stdenv buildPackages.distccWrapper); + + distccMasquerade = if stdenv.isDarwin + then null + else callPackage ../development/tools/misc/distcc/masq.nix { + gccRaw = gcc.cc; + binutils = binutils; + }; + + dive = callPackage ../development/tools/dive { }; + + doclifter = callPackage ../development/tools/misc/doclifter { }; + + docutils = with python3Packages; toPythonApplication docutils; + + doctl = callPackage ../development/tools/doctl { }; + + doit = callPackage ../development/tools/build-managers/doit { }; + + dot2tex = pythonPackages.dot2tex; + + doxygen = callPackage ../development/tools/documentation/doxygen { + qt4 = null; + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + doxygen_gui = lowPrio (doxygen.override { inherit qt4; }); + + drake = callPackage ../development/tools/build-managers/drake { }; + + drip = callPackage ../development/tools/drip { }; + + drm_info = callPackage ../development/tools/drm_info { }; + + drush = callPackage ../development/tools/misc/drush { }; + + editorconfig-core-c = callPackage ../development/tools/misc/editorconfig-core-c { }; + + eggdbus = callPackage ../development/tools/misc/eggdbus { }; + + egypt = callPackage ../development/tools/analysis/egypt { }; + + elfinfo = callPackage ../development/tools/misc/elfinfo { }; + + elfkickers = callPackage ../development/tools/misc/elfkickers { }; + + elfutils = callPackage ../development/tools/misc/elfutils { }; + + emma = callPackage ../development/tools/analysis/emma { }; + + epm = callPackage ../development/tools/misc/epm { }; + + eresi = callPackage ../development/tools/analysis/eresi { }; + + evmdis = callPackage ../development/tools/analysis/evmdis { }; + + eweb = callPackage ../development/tools/literate-programming/eweb { }; + + eztrace = callPackage ../development/tools/profiling/EZTrace { }; + + ezquake = callPackage ../games/ezquake { }; + + findbugs = callPackage ../development/tools/analysis/findbugs { }; + + findnewest = callPackage ../development/tools/misc/findnewest { }; + + flootty = callPackage ../development/tools/flootty { }; + + fffuu = haskell.lib.justStaticExecutables (haskellPackages.callPackage ../tools/misc/fffuu { }); + + flow = callPackage ../development/tools/analysis/flow { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + fly = callPackage ../development/tools/continuous-integration/fly { }; + + foreman = callPackage ../tools/system/foreman { }; + goreman = callPackage ../tools/system/goreman { }; + + framac = callPackage ../development/tools/analysis/frama-c { }; + + frame = callPackage ../development/libraries/frame { }; + + fsatrace = callPackage ../development/tools/misc/fsatrace { }; + + fswatch = callPackage ../development/tools/misc/fswatch { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + funnelweb = callPackage ../development/tools/literate-programming/funnelweb { }; + + gede = libsForQt59.callPackage ../development/tools/misc/gede { }; + + gdbgui = python3Packages.callPackage ../development/tools/misc/gdbgui { }; + + pmd = callPackage ../development/tools/analysis/pmd { }; + + pmdk = callPackage ../development/libraries/pmdk { }; + + jdepend = callPackage ../development/tools/analysis/jdepend { }; + + fedpkg = pythonPackages.callPackage ../development/tools/fedpkg { }; + + flex_2_5_35 = callPackage ../development/tools/parsing/flex/2.5.35.nix { }; + flex = callPackage ../development/tools/parsing/flex { }; + + flexibee = callPackage ../applications/office/flexibee { }; + + flexcpp = callPackage ../development/tools/parsing/flexc++ { }; + + geis = callPackage ../development/libraries/geis { + inherit (xorg) libX11 libXext libXi libXtst; + }; + + github-release = callPackage ../development/tools/github/github-release { }; + + global = callPackage ../development/tools/misc/global { }; + + gnome-doc-utils = callPackage ../development/tools/documentation/gnome-doc-utils {}; + + gnome-desktop-testing = callPackage ../development/tools/gnome-desktop-testing {}; + + gnome-hexgl = callPackage ../games/gnome-hexgl {}; + + gnome-usage = callPackage ../applications/misc/gnome-usage {}; + + gnome-latex = callPackage ../applications/editors/gnome-latex/default.nix { }; + + gnome-online-accounts = callPackage ../development/libraries/gnome-online-accounts { }; + + gnome-video-effects = callPackage ../development/libraries/gnome-video-effects { }; + + gnum4 = callPackage ../development/tools/misc/gnum4 { }; + m4 = gnum4; + + gnumake42 = callPackage ../development/tools/build-managers/gnumake/4.2 { }; + gnumake = gnumake42; + + gnustep = recurseIntoAttrs (callPackage ../desktops/gnustep {}); + + gob2 = callPackage ../development/tools/misc/gob2 { }; + + gocd-agent = callPackage ../development/tools/continuous-integration/gocd-agent { }; + + gocd-server = callPackage ../development/tools/continuous-integration/gocd-server { }; + + gotty = callPackage ../servers/gotty { }; + + gputils = callPackage ../development/tools/misc/gputils { }; + + gradleGen = callPackage ../development/tools/build-managers/gradle { + java = jdk; + }; + gradle = res.gradleGen.gradle_latest; + gradle_2_5 = res.gradleGen.gradle_2_5; + gradle_2_14 = res.gradleGen.gradle_2_14; + gradle_3_5 = res.gradleGen.gradle_3_5; + gradle_4_10 = res.gradleGen.gradle_4_10; + gradle_2 = gradle_2_14; + gradle_3 = gradle_3_5; + gradle_4 = gradle_4_10; + gradle_5 = res.gradleGen.gradle_5_3; + + gperf = callPackage ../development/tools/misc/gperf { }; + # 3.1 changed some parameters from int to size_t, leading to mismatches. + gperf_3_0 = callPackage ../development/tools/misc/gperf/3.0.x.nix { }; + + grail = callPackage ../development/libraries/grail { }; + + graphene-hardened-malloc = callPackage ../development/libraries/graphene-hardened-malloc { }; + + graphene = callPackage ../development/libraries/graphene { }; + + gtk-doc = callPackage ../development/tools/documentation/gtk-doc { }; + + gtkdialog = callPackage ../development/tools/misc/gtkdialog { }; + + gtranslator = callPackage ../tools/text/gtranslator { }; + + guff = callPackage ../tools/graphics/guff { }; + + guile-lint = callPackage ../development/tools/guile/guile-lint { + guile = guile_1_8; + }; + + gwrap = callPackage ../development/tools/guile/g-wrap { + guile = guile_2_0; + }; + + hcloud = callPackage ../development/tools/hcloud { }; + + help2man = callPackage ../development/tools/misc/help2man { }; + + heroku = callPackage ../development/tools/heroku { + nodejs = nodejs-10_x; + }; + + htmlunit-driver = callPackage ../development/tools/selenium/htmlunit-driver { }; + + hyenae = callPackage ../tools/networking/hyenae { }; + + iaca_2_1 = callPackage ../development/tools/iaca/2.1.nix { }; + iaca_3_0 = callPackage ../development/tools/iaca/3.0.nix { }; + iaca = iaca_3_0; + + icestorm = callPackage ../development/tools/icestorm { }; + + icmake = callPackage ../development/tools/build-managers/icmake { }; + + iconnamingutils = callPackage ../development/tools/misc/icon-naming-utils { }; + + ikos = callPackage ../development/tools/analysis/ikos { + inherit (llvmPackages_7) stdenv clang llvm; + }; + + include-what-you-use = callPackage ../development/tools/analysis/include-what-you-use { + llvmPackages = llvmPackages_6; + }; + + indent = callPackage ../development/tools/misc/indent { }; + + ino = callPackage ../development/arduino/ino { }; + + inotify-tools = callPackage ../development/tools/misc/inotify-tools { }; + + intel-gpu-tools = callPackage ../development/tools/misc/intel-gpu-tools { }; + + insomnia = callPackage ../development/web/insomnia { }; + + iozone = callPackage ../development/tools/misc/iozone { }; + + itstool = callPackage ../development/tools/misc/itstool { }; + + jam = callPackage ../development/tools/build-managers/jam { }; + + jamomacore = callPackage ../development/libraries/audio/jamomacore { }; + + jbake = callPackage ../development/tools/jbake { }; + + jikespg = callPackage ../development/tools/parsing/jikespg { }; + + jenkins = callPackage ../development/tools/continuous-integration/jenkins { }; + + jenkins-job-builder = pythonPackages.jenkins-job-builder; + + kafkacat = callPackage ../development/tools/kafkacat { }; + + kati = callPackage ../development/tools/build-managers/kati { }; + + kconfig-frontends = callPackage ../development/tools/misc/kconfig-frontends { + gperf = gperf_3_0; + }; + + kcgi = callPackage ../development/web/kcgi { }; + + kcov = callPackage ../development/tools/analysis/kcov { }; + + kind = callPackage ../development/tools/kind { }; + + kube-aws = callPackage ../development/tools/kube-aws { }; + + kubectx = callPackage ../development/tools/kubectx { }; + + kube-prompt = callPackage ../development/tools/kube-prompt { }; + + kubicorn = callPackage ../development/tools/kubicorn { }; + + kustomize = callPackage ../development/tools/kustomize { }; + + ktlint = callPackage ../development/tools/ktlint { }; + + kythe = callPackage ../development/tools/kythe { }; + + lazygit = callPackage ../development/tools/lazygit { }; + + Literate = callPackage ../development/tools/literate-programming/Literate {}; + + lcov = callPackage ../development/tools/analysis/lcov { }; + + leiningen = callPackage ../development/tools/build-managers/leiningen { }; + + lemon = callPackage ../development/tools/parsing/lemon { }; + + lenmus = callPackage ../applications/misc/lenmus { }; + + libtool = libtool_2; + + libtool_1_5 = callPackage ../development/tools/misc/libtool { }; + + libtool_2 = callPackage ../development/tools/misc/libtool/libtool2.nix { }; + + libwhich = callPackage ../development/tools/misc/libwhich { }; + + linuxkit = callPackage ../development/tools/misc/linuxkit { }; + + lit = callPackage ../development/tools/misc/lit { }; + + litecli = callPackage ../development/tools/database/litecli {}; + + lsof = callPackage ../development/tools/misc/lsof { }; + + ltrace = callPackage ../development/tools/misc/ltrace { }; + + lttng-tools = callPackage ../development/tools/misc/lttng-tools { }; + + lttng-ust = callPackage ../development/tools/misc/lttng-ust { }; + + lttv = callPackage ../development/tools/misc/lttv { }; + + massif-visualizer = libsForQt5.callPackage ../development/tools/analysis/massif-visualizer { }; + + maven = maven3; + maven3 = callPackage ../development/tools/build-managers/apache-maven { }; + + go-md2man = callPackage ../development/tools/misc/md2man {}; + + mage = callPackage ../development/tools/build-managers/mage { }; + + mbed-cli = callPackage ../development/tools/mbed-cli { }; + + mdl = callPackage ../development/tools/misc/mdl { }; + + minify = callPackage ../development/web/minify { }; + + minizinc = callPackage ../development/tools/minizinc { }; + minizincide = qt5.callPackage ../development/tools/minizinc/ide.nix { }; + + mk = callPackage ../development/tools/build-managers/mk { }; + + mkcert = callPackage ../development/tools/misc/mkcert { }; + + mkdocs = callPackage ../development/tools/documentation/mkdocs { }; + + moby = callPackage ../development/tools/misc/moby { }; + + modd = callPackage ../development/tools/modd { }; + + msgpack-tools = callPackage ../development/tools/msgpack-tools { }; + + msgpuck = callPackage ../development/libraries/msgpuck { }; + + msitools = callPackage ../development/tools/misc/msitools { }; + + haskell-ci = haskell.lib.justStaticExecutables haskellPackages.haskell-ci; + + neoload = callPackage ../development/tools/neoload { + licenseAccepted = (config.neoload.accept_license or false); + fontsConf = makeFontsConf { + fontDirectories = [ + dejavu_fonts.minimal + ]; + }; + }; + + nailgun = callPackage ../development/tools/nailgun { }; + + ninja = callPackage ../development/tools/build-managers/ninja { }; + + gn = callPackage ../development/tools/build-managers/gn { }; + + nixbang = callPackage ../development/tools/misc/nixbang { + pythonPackages = python3Packages; + }; + + nexus = callPackage ../development/tools/repository-managers/nexus { }; + + nwjs = callPackage ../development/tools/nwjs { + gconf = pkgs.gnome2.GConf; + }; + + nwjs-sdk = callPackage ../development/tools/nwjs { + gconf = pkgs.gnome2.GConf; + sdk = true; + }; + + # only kept for nixui, see https://github.com/matejc/nixui/issues/27 + nwjs_0_12 = callPackage ../development/tools/node-webkit/nw12.nix { + gconf = pkgs.gnome2.GConf; + }; + + # NOTE: Override and set icon-lang = null to use Awk instead of Icon. + noweb = callPackage ../development/tools/literate-programming/noweb { }; + + nuweb = callPackage ../development/tools/literate-programming/nuweb { tex = texlive.combined.scheme-small; }; + + nrfutil = callPackage ../development/tools/misc/nrfutil { }; + + obelisk = callPackage ../development/tools/ocaml/obelisk { }; + + obuild = callPackage ../development/tools/ocaml/obuild { }; + + omake = callPackage ../development/tools/ocaml/omake { }; + + omniorb = callPackage ../development/tools/omniorb { }; + + opengrok = callPackage ../development/tools/misc/opengrok { }; + + openocd = callPackage ../development/tools/misc/openocd { }; + + oprofile = callPackage ../development/tools/profiling/oprofile { + libiberty_static = libiberty.override { staticBuild = true; }; + }; + + pahole = callPackage ../development/tools/misc/pahole {}; + + panopticon = callPackage ../development/tools/analysis/panopticon {}; + + pants = callPackage ../development/tools/build-managers/pants {}; + + parinfer-rust = callPackage ../development/tools/parinfer-rust {}; + + parse-cli-bin = callPackage ../development/tools/parse-cli-bin { }; + + patchelf = callPackage ../development/tools/misc/patchelf { }; + + patchelfUnstable = lowPrio (callPackage ../development/tools/misc/patchelf/unstable.nix { }); + + pax-rs = callPackage ../development/tools/pax-rs { }; + + peg = callPackage ../development/tools/parsing/peg { }; + + pgcli = callPackage ../development/tools/database/pgcli {}; + + phantomjs = callPackage ../development/tools/phantomjs { }; + + phantomjs2 = libsForQt5.callPackage ../development/tools/phantomjs2 { }; + + pmccabe = callPackage ../development/tools/misc/pmccabe { }; + + pkgconf = callPackage ../development/tools/misc/pkgconf {}; + + pkg-config = callPackage ../development/tools/misc/pkg-config { }; + pkgconfig = pkg-config; # added 2018-02-02 + + pkg-configUpstream = lowPrio (pkg-config.override { vanilla = true; }); + pkgconfigUpstream = pkg-configUpstream; # added 2018-02-02 + + postiats-utilities = callPackage ../development/tools/postiats-utilities {}; + + postman = callPackage ../development/web/postman {}; + + pprof = callPackage ../development/tools/profiling/pprof { }; + + pyprof2calltree = with python3Packages; toPythonApplication pyprof2calltree; + + prelink = callPackage ../development/tools/misc/prelink { }; + + premake3 = callPackage ../development/tools/misc/premake/3.nix { }; + + premake4 = callPackage ../development/tools/misc/premake { }; + + premake5 = callPackage ../development/tools/misc/premake/5.nix { + inherit (darwin.apple_sdk.frameworks) Foundation; + }; + + premake = premake4; + + procodile = callPackage ../tools/system/procodile { }; + + pup = callPackage ../development/tools/pup { }; + + puppet-lint = callPackage ../development/tools/puppet/puppet-lint { }; + + pyflame = callPackage ../development/tools/profiling/pyflame { }; + + pyrseas = callPackage ../development/tools/database/pyrseas { }; + + qtcreator = libsForQt5.callPackage ../development/tools/qtcreator { }; + + r10k = callPackage ../tools/system/r10k { }; + + inherit (callPackages ../development/tools/analysis/radare2 ({ + inherit (gnome2) vte; + lua = lua5; + } // (config.radare or {}))) radare2 r2-for-cutter; + + radare2-cutter = libsForQt5.callPackage ../development/tools/analysis/radare2/cutter.nix { }; + + ragel = ragelStable; + + randoop = callPackage ../development/tools/analysis/randoop { }; + + inherit (callPackages ../development/tools/parsing/ragel { + tex = texlive.combined.scheme-small; + }) ragelStable ragelDev; + + hammer = callPackage ../development/tools/parsing/hammer { }; + + rdocker = callPackage ../development/tools/rdocker { }; + + redis-dump = callPackage ../development/tools/redis-dump { }; + + redo = callPackage ../development/tools/build-managers/redo { }; + + redo-apenwarr = callPackage ../development/tools/build-managers/redo-apenwarr { }; + + redo-sh = callPackage ../development/tools/build-managers/redo-sh { }; + + reno = callPackage ../development/tools/reno { }; + + re2c = callPackage ../development/tools/parsing/re2c { }; + + remake = callPackage ../development/tools/build-managers/remake { }; + + retdec = callPackage ../development/tools/analysis/retdec { }; + retdec-full = retdec.override { + withPEPatterns = true; + }; + + reviewdog = callPackage ../development/tools/misc/reviewdog { }; + + rman = callPackage ../development/tools/misc/rman { }; + + rolespec = callPackage ../development/tools/misc/rolespec { }; + + rr = callPackage ../development/tools/analysis/rr { }; + + saleae-logic = callPackage ../development/tools/misc/saleae-logic { }; + + sauce-connect = callPackage ../development/tools/sauce-connect { }; + + selenium-server-standalone = callPackage ../development/tools/selenium/server { }; + + selendroid = callPackage ../development/tools/selenium/selendroid { }; + + semver-tool = callPackage ../development/tools/misc/semver-tool { }; + + sconsPackages = dontRecurseIntoAttrs (callPackage ../development/tools/build-managers/scons { }); + scons = sconsPackages.scons_latest; + + mill = callPackage ../development/tools/build-managers/mill { }; + + sbt = callPackage ../development/tools/build-managers/sbt { }; + sbt-with-scala-native = callPackage ../development/tools/build-managers/sbt/scala-native.nix { }; + simpleBuildTool = sbt; + + sbt-extras = callPackage ../development/tools/build-managers/sbt-extras { }; + + scss-lint = callPackage ../development/tools/scss-lint { }; + + shake = haskell.lib.justStaticExecutables haskellPackages.shake; + + shallot = callPackage ../tools/misc/shallot { }; + + shards = callPackage ../development/tools/build-managers/shards { }; + + shellcheck = haskell.lib.justStaticExecutables haskellPackages.ShellCheck; + + schemaspy = callPackage ../development/tools/database/schemaspy { }; + + shncpd = callPackage ../tools/networking/shncpd { }; + + sigrok-cli = callPackage ../development/tools/sigrok-cli { }; + + simpleTpmPk11 = callPackage ../tools/security/simple-tpm-pk11 { }; + + slimerjs = callPackage ../development/tools/slimerjs {}; + + sloccount = callPackage ../development/tools/misc/sloccount { }; + + sloc = nodePackages.sloc; + + smatch = callPackage ../development/tools/analysis/smatch { + buildllvmsparse = false; + buildc2xml = false; + }; + + smc = callPackage ../tools/misc/smc { }; + + snakemake = callPackage ../applications/science/misc/snakemake { python = python3Packages; }; + + snowman = qt5.callPackage ../development/tools/analysis/snowman { }; + + sparse = callPackage ../development/tools/analysis/sparse { }; + + speedtest-cli = with python3Packages; toPythonApplication speedtest-cli; + + spin = callPackage ../development/tools/analysis/spin { }; + + spirv-headers = callPackage ../development/libraries/spirv-headers { }; + spirv-tools = callPackage ../development/tools/spirv-tools { }; + + splint = callPackage ../development/tools/analysis/splint { + flex = flex_2_5_35; + }; + + spoofer = callPackage ../tools/networking/spoofer { }; + + spoofer-gui = callPackage ../tools/networking/spoofer { withGUI = true; }; + + spooles = callPackage ../development/libraries/science/math/spooles {}; + + sqlcheck = callPackage ../development/tools/database/sqlcheck { }; + + sqlitebrowser = libsForQt5.callPackage ../development/tools/database/sqlitebrowser { }; + + sqlite-web = callPackage ../development/tools/database/sqlite-web { }; + + sselp = callPackage ../tools/X11/sselp{ }; + + stm32flash = callPackage ../development/tools/misc/stm32flash { }; + + strace = callPackage ../development/tools/misc/strace { }; + + swarm = callPackage ../development/tools/analysis/swarm { }; + + swig1 = callPackage ../development/tools/misc/swig { }; + swig2 = callPackage ../development/tools/misc/swig/2.x.nix { }; + swig3 = callPackage ../development/tools/misc/swig/3.x.nix { }; + swig4 = callPackage ../development/tools/misc/swig/4.nix { }; + swig = swig3; + swigWithJava = swig; + + swfmill = callPackage ../tools/video/swfmill { }; + + swftools = callPackage ../tools/video/swftools { + stdenv = gccStdenv; + }; + + tcptrack = callPackage ../development/tools/misc/tcptrack { }; + + teensyduino = arduino-core.override { withGui = true; withTeensyduino = true; }; + + teensy-loader-cli = callPackage ../development/tools/misc/teensy-loader-cli { }; + + terracognita = callPackage ../development/tools/misc/terracognita { }; + + terraform-lsp = callPackage ../development/tools/misc/terraform-lsp { }; + + texinfo413 = callPackage ../development/tools/misc/texinfo/4.13a.nix { }; + texinfo4 = texinfo413; + texinfo5 = callPackage ../development/tools/misc/texinfo/5.2.nix { }; + texinfo6 = callPackage ../development/tools/misc/texinfo/6.5.nix { }; + texinfo = texinfo6; + texinfoInteractive = appendToName "interactive" ( + texinfo.override { interactive = true; } + ); + + texi2html = callPackage ../development/tools/misc/texi2html { }; + + texi2mdoc = callPackage ../tools/misc/texi2mdoc { }; + + tflint = callPackage ../development/tools/analysis/tflint { }; + + todoist = callPackage ../applications/misc/todoist { }; + + todolist = callPackage ../applications/misc/todolist { }; + + travis = callPackage ../development/tools/misc/travis { }; + + tree-sitter = callPackage ../development/tools/parsing/tree-sitter { }; + + trellis = callPackage ../development/tools/trellis { }; + + ttyd = callPackage ../servers/ttyd { }; + + tweak = callPackage ../applications/editors/tweak { }; + + tychus = callPackage ../development/tools/tychus { + inherit (darwin.apple_sdk.frameworks) CoreFoundation; + }; + + uefi-firmware-parser = callPackage ../development/tools/analysis/uefi-firmware-parser { }; + + uhd = callPackage ../applications/radio/uhd { }; + + uisp = callPackage ../development/tools/misc/uisp { }; + + uncrustify = callPackage ../development/tools/misc/uncrustify { }; + + universal-ctags = callPackage ../development/tools/misc/universal-ctags { }; + + vagrant = callPackage ../development/tools/vagrant {}; + + bashdb = callPackage ../development/tools/misc/bashdb { }; + + gdb = callPackage ../development/tools/misc/gdb { + guile = null; + }; + + jhiccup = callPackage ../development/tools/java/jhiccup { }; + + valgrind = callPackage ../development/tools/analysis/valgrind { + inherit (buildPackages.darwin) xnu bootstrap_cmds cctools; + }; + valgrind-light = res.valgrind.override { gdb = null; }; + + valkyrie = callPackage ../development/tools/analysis/valkyrie { }; + + qcachegrind = libsForQt5.callPackage ../development/tools/analysis/qcachegrind {}; + + visualvm = callPackage ../development/tools/java/visualvm { }; + + vultr = callPackage ../development/tools/vultr { }; + + vulnix = callPackage ../tools/security/vulnix { + pythonPackages = python3Packages; + }; + + vtable-dumper = callPackage ../development/tools/misc/vtable-dumper { }; + + whatstyle = callPackage ../development/tools/misc/whatstyle { + inherit (llvmPackages) clang-unwrapped; + }; + + watson-ruby = callPackage ../development/tools/misc/watson-ruby {}; + + xc3sprog = callPackage ../development/tools/misc/xc3sprog { }; + + xcodebuild = callPackage ../development/tools/xcbuild/wrapper.nix { + inherit (darwin.apple_sdk.frameworks) CoreServices CoreGraphics ImageIO; + }; + xcodebuild6 = xcodebuild.override { stdenv = llvmPackages_6.stdenv; }; + xcbuild = xcodebuild; + xcbuildHook = makeSetupHook { + deps = [ xcbuild ]; + } ../development/tools/xcbuild/setup-hook.sh ; + + # xcbuild with llvm 6 + xcbuild6Hook = makeSetupHook { + deps = [ xcodebuild6 ]; + } ../development/tools/xcbuild/setup-hook.sh ; + + xcpretty = callPackage ../development/tools/xcpretty { }; + + xmlindent = callPackage ../development/web/xmlindent {}; + + xpwn = callPackage ../development/mobile/xpwn {}; + + xxdiff = callPackage ../development/tools/misc/xxdiff { + bison = bison2; + }; + xxdiff-tip = libsForQt5.callPackage ../development/tools/misc/xxdiff/tip.nix { }; + + yaml2json = callPackage ../development/tools/yaml2json { }; + + ycmd = callPackage ../development/tools/misc/ycmd { + inherit (darwin.apple_sdk.frameworks) Cocoa; + python = python3; + }; + + yodl = callPackage ../development/tools/misc/yodl { }; + + yq = callPackage ../development/tools/yq { + inherit (python3Packages) buildPythonApplication fetchPypi pyyaml xmltodict; + }; + + winpdb = callPackage ../development/tools/winpdb { }; + + grabserial = callPackage ../development/tools/grabserial { }; + + mypy = with python3Packages; toPythonApplication mypy; + + nsis = callPackage ../development/tools/nsis { }; + + ### DEVELOPMENT / LIBRARIES + + a52dec = callPackage ../development/libraries/a52dec { }; + + aalib = callPackage ../development/libraries/aalib { }; + + abseil-cpp = callPackage ../development/libraries/abseil-cpp { }; + + accountsservice = callPackage ../development/libraries/accountsservice { }; + + acl = callPackage ../development/libraries/acl { }; + + acsccid = callPackage ../tools/security/acsccid { }; + + activemq = callPackage ../development/libraries/apache-activemq { }; + + adns = callPackage ../development/libraries/adns { }; + + afflib = callPackage ../development/libraries/afflib { }; + + aften = callPackage ../development/libraries/aften { }; + + alure = callPackage ../development/libraries/alure { }; + + agg = callPackage ../development/libraries/agg { }; + + allegro = allegro4; + allegro4 = callPackage ../development/libraries/allegro {}; + allegro5 = callPackage ../development/libraries/allegro/5.nix {}; + + amrnb = callPackage ../development/libraries/amrnb { }; + + amrwb = callPackage ../development/libraries/amrwb { }; + + anttweakbar = callPackage ../development/libraries/AntTweakBar { }; + + appstream = callPackage ../development/libraries/appstream { }; + + appstream-glib = callPackage ../development/libraries/appstream-glib { }; + + appstream-qt = libsForQt5.callPackage ../development/libraries/appstream/qt.nix { }; + + apr = callPackage ../development/libraries/apr { }; + + aprutil = callPackage ../development/libraries/apr-util { + db = if stdenv.isFreeBSD then db4 else db; + # XXX: only the db_185 interface was available through + # apr with db58 on freebsd (nov 2015), for unknown reasons + }; + + aravis = callPackage ../development/libraries/aravis { + inherit (gst_all_1) gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad; + }; + + arb = callPackage ../development/libraries/arb {}; + + argp-standalone = callPackage ../development/libraries/argp-standalone {}; + + armadillo = callPackage ../development/libraries/armadillo {}; + + arrow-cpp = callPackage ../development/libraries/arrow-cpp { + gtest = gtest.override { static = true; }; + }; + + assimp = callPackage ../development/libraries/assimp { }; + + asio = asio_1_12; + asio_1_10 = callPackage ../development/libraries/asio/1.10.nix { }; + asio_1_12 = callPackage ../development/libraries/asio/1.12.nix { }; + + aspell = callPackage ../development/libraries/aspell { }; + + aspellDicts = recurseIntoAttrs (callPackages ../development/libraries/aspell/dictionaries.nix {}); + + aspellWithDicts = callPackage ../development/libraries/aspell/aspell-with-dicts.nix { + aspell = aspell.override { searchNixProfiles = false; }; + }; + + attica = callPackage ../development/libraries/attica { }; + + attr = callPackage ../development/libraries/attr { }; + + at-spi2-core = callPackage ../development/libraries/at-spi2-core { }; + + at-spi2-atk = callPackage ../development/libraries/at-spi2-atk { }; + + aqbanking = callPackage ../development/libraries/aqbanking { }; + + aubio = callPackage ../development/libraries/aubio { }; + + audiofile = callPackage ../development/libraries/audiofile { + inherit (darwin.apple_sdk.frameworks) AudioUnit CoreServices; + }; + + aws-c-common = callPackage ../development/libraries/aws-c-common { }; + + aws-c-event-stream = callPackage ../development/libraries/aws-c-event-stream { }; + + aws-checksums = callPackage ../development/libraries/aws-checksums { }; + + aws-sdk-cpp = callPackage ../development/libraries/aws-sdk-cpp { + inherit (darwin.apple_sdk.frameworks) CoreAudio AudioToolbox; + }; + + babl = callPackage ../development/libraries/babl { }; + + backward-cpp = callPackage ../development/libraries/backward-cpp { }; + + bamf = callPackage ../development/libraries/bamf { }; + + bctoolbox = callPackage ../development/libraries/bctoolbox { + mbedtls = mbedtls_1_3; + }; + + beecrypt = callPackage ../development/libraries/beecrypt { }; + + belcard = callPackage ../development/libraries/belcard { }; + + belr = callPackage ../development/libraries/belr { }; + + beignet = callPackage ../development/libraries/beignet { + inherit (llvmPackages_6) llvm clang-unwrapped; + }; + + belle-sip = callPackage ../development/libraries/belle-sip { }; + + libbfd = callPackage ../development/libraries/libbfd { }; + + libopcodes = callPackage ../development/libraries/libopcodes { }; + + bicpl = callPackage ../development/libraries/science/biology/bicpl { }; + + bicgl = callPackage ../development/libraries/science/biology/bicgl { }; + + # TODO(@Ericson2314): Build bionic libc from source + bionic = assert stdenv.hostPlatform.useAndroidPrebuilt; + pkgs."androidndkPkgs_${stdenv.hostPlatform.ndkVer}".libraries; + + bobcat = callPackage ../development/libraries/bobcat { }; + + boehmgc = callPackage ../development/libraries/boehm-gc { }; + boehmgc_766 = callPackage ../development/libraries/boehm-gc/7.6.6.nix { }; + + boolstuff = callPackage ../development/libraries/boolstuff { }; + + boost155 = callPackage ../development/libraries/boost/1.55.nix { }; + boost159 = callPackage ../development/libraries/boost/1.59.nix { }; + boost15x = boost159; + boost160 = callPackage ../development/libraries/boost/1.60.nix { }; + boost162 = callPackage ../development/libraries/boost/1.62.nix { }; + boost163 = callPackage ../development/libraries/boost/1.63.nix { }; + boost164 = callPackage ../development/libraries/boost/1.64.nix { }; + boost165 = callPackage ../development/libraries/boost/1.65.nix { }; + boost166 = callPackage ../development/libraries/boost/1.66.nix { }; + boost167 = callPackage ../development/libraries/boost/1.67.nix { }; + boost168 = callPackage ../development/libraries/boost/1.68.nix { }; + boost169 = callPackage ../development/libraries/boost/1.69.nix { }; + boost16x = boost167; + boost170 = callPackage ../development/libraries/boost/1.70.nix { }; + boost17x = boost170; + boost = boost16x; + + boost_process = callPackage ../development/libraries/boost-process { }; + + botan = callPackage ../development/libraries/botan { openssl = openssl_1_0_2; }; + botan2 = callPackage ../development/libraries/botan/2.0.nix { }; + + box2d = callPackage ../development/libraries/box2d { }; + + buddy = callPackage ../development/libraries/buddy { }; + + bulletml = callPackage ../development/libraries/bulletml { }; + + bwidget = callPackage ../development/libraries/bwidget { }; + + bzrtp = callPackage ../development/libraries/bzrtp { }; + + c-ares = callPackage ../development/libraries/c-ares { }; + + c-blosc = callPackage ../development/libraries/c-blosc { }; + + cachix = haskell.lib.justStaticExecutables haskellPackages.cachix; + + capnproto = callPackage ../development/libraries/capnproto { }; + + captive-browser = callPackage ../applications/networking/browsers/captive-browser { }; + + ndn-cxx = callPackage ../development/libraries/ndn-cxx { }; + + cddlib = callPackage ../development/libraries/cddlib {}; + + cdk = callPackage ../development/libraries/cdk {}; + + cdo = callPackage ../development/libraries/cdo { }; + + cimg = callPackage ../development/libraries/cimg { }; + + scmccid = callPackage ../development/libraries/scmccid { }; + + ccrtp = callPackage ../development/libraries/ccrtp { }; + + ccrtp_1_8 = callPackage ../development/libraries/ccrtp/1.8.nix { }; + + cctz = callPackage ../development/libraries/cctz { }; + + celt = callPackage ../development/libraries/celt {}; + celt_0_7 = callPackage ../development/libraries/celt/0.7.nix {}; + celt_0_5_1 = callPackage ../development/libraries/celt/0.5.1.nix {}; + + cegui = callPackage ../development/libraries/cegui { + ogre = ogre1_10; + }; + + certbot = callPackage ../tools/admin/certbot { }; + + caf = callPackage ../development/libraries/caf {}; + + cgal = callPackage ../development/libraries/CGAL {}; + + cgui = callPackage ../development/libraries/cgui {}; + + check = callPackage ../development/libraries/check { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + chipmunk = callPackage ../development/libraries/chipmunk {}; + + chmlib = callPackage ../development/libraries/chmlib { }; + + chromaprint = callPackage ../development/libraries/chromaprint { }; + + cl = callPackage ../development/libraries/cl { }; + + classads = callPackage ../development/libraries/classads { }; + + clearsilver = callPackage ../development/libraries/clearsilver { }; + + clipper = callPackage ../development/libraries/clipper { }; + + cln = callPackage ../development/libraries/cln { }; + + clucene_core_2 = callPackage ../development/libraries/clucene-core/2.x.nix { + stdenv = if stdenv.cc.isClang then llvmPackages_6.stdenv else stdenv; + }; + + clucene_core_1 = callPackage ../development/libraries/clucene-core { + stdenv = if stdenv.cc.isClang then llvmPackages_6.stdenv else stdenv; + }; + + clucene_core = clucene_core_1; + + clutter = callPackage ../development/libraries/clutter { }; + + clutter-gst = callPackage ../development/libraries/clutter-gst { + }; + + clutter-gtk = callPackage ../development/libraries/clutter-gtk { }; + + cminpack = callPackage ../development/libraries/cminpack { }; + + cmocka = callPackage ../development/libraries/cmocka { }; + + cmrt = callPackage ../development/libraries/cmrt { }; + + cogl = callPackage ../development/libraries/cogl { }; + + coin3d = callPackage ../development/libraries/coin3d { }; + + soxt = callPackage ../development/libraries/soxt { }; + + CoinMP = callPackage ../development/libraries/CoinMP { }; + + cointop = callPackage ../applications/misc/cointop { }; + + commoncpp2 = callPackage ../development/libraries/commoncpp2 { }; + + coredumper = callPackage ../development/libraries/coredumper { }; + + ctl = callPackage ../development/libraries/ctl { }; + + ctpp2 = callPackage ../development/libraries/ctpp2 { }; + + ctpl = callPackage ../development/libraries/ctpl { }; + + cppdb = callPackage ../development/libraries/cppdb { }; + + cpp-utilities = callPackage ../development/libraries/cpp-utilities { }; + + cpp-hocon = callPackage ../development/libraries/cpp-hocon { }; + + cpp-ipfs-api = callPackage ../development/libraries/cpp-ipfs-api { }; + + cpp-netlib = callPackage ../development/libraries/cpp-netlib { + openssl = openssl_1_0_2; + }; + uri = callPackage ../development/libraries/uri { }; + + cppcms = callPackage ../development/libraries/cppcms { }; + + cppunit = callPackage ../development/libraries/cppunit { }; + + cpputest = callPackage ../development/libraries/cpputest { }; + + cracklib = callPackage ../development/libraries/cracklib { }; + + cre2 = callPackage ../development/libraries/cre2 { }; + + croaring = callPackage ../development/libraries/croaring { }; + + cryptopp = callPackage ../development/libraries/crypto++ { }; + + cryptominisat = callPackage ../applications/science/logic/cryptominisat { }; + + ctypes_sh = callPackage ../development/libraries/ctypes_sh { }; + + curlcpp = callPackage ../development/libraries/curlcpp { }; + + curlpp = callPackage ../development/libraries/curlpp { }; + + cutee = callPackage ../development/libraries/cutee { }; + + cutelyst = libsForQt5.callPackage ../development/libraries/cutelyst { }; + + cxxtools = callPackage ../development/libraries/cxxtools { }; + + cwiid = callPackage ../development/libraries/cwiid { }; + + cxx-prettyprint = callPackage ../development/libraries/cxx-prettyprint { }; + + cxxtest = callPackage ../development/libraries/cxxtest { }; + + cypress = callPackage ../development/web/cypress { }; + + cyrus_sasl = callPackage ../development/libraries/cyrus-sasl { + kerberos = if stdenv.isFreeBSD then libheimdal else kerberos; + }; + + # Make bdb5 the default as it is the last release under the custom + # bsd-like license + db = db5; + db4 = db48; + db48 = callPackage ../development/libraries/db/db-4.8.nix { }; + db5 = db53; + db53 = callPackage ../development/libraries/db/db-5.3.nix { }; + db6 = db60; + db60 = callPackage ../development/libraries/db/db-6.0.nix { }; + db62 = callPackage ../development/libraries/db/db-6.2.nix { }; + + dbxml = callPackage ../development/libraries/dbxml { }; + + dbus = callPackage ../development/libraries/dbus { }; + dbus_cplusplus = callPackage ../development/libraries/dbus-cplusplus { }; + dbus-glib = callPackage ../development/libraries/dbus-glib { }; + dbus_java = callPackage ../development/libraries/java/dbus-java { }; + + dbus-sharp-1_0 = callPackage ../development/libraries/dbus-sharp/dbus-sharp-1.0.nix { }; + dbus-sharp-2_0 = callPackage ../development/libraries/dbus-sharp { }; + + dbus-sharp-glib-1_0 = callPackage ../development/libraries/dbus-sharp-glib/dbus-sharp-glib-1.0.nix { }; + dbus-sharp-glib-2_0 = callPackage ../development/libraries/dbus-sharp-glib { }; + + makeDBusConf = { suidHelper, serviceDirectories }: + callPackage ../development/libraries/dbus/make-dbus-conf.nix { + inherit suidHelper serviceDirectories; + }; + + dee = callPackage ../development/libraries/dee { }; + + dhex = callPackage ../applications/editors/dhex { }; + + double-conversion = callPackage ../development/libraries/double-conversion { }; + + dclib = callPackage ../development/libraries/dclib { }; + + dillo = callPackage ../applications/networking/browsers/dillo { + fltk = fltk13; + }; + + dirac = callPackage ../development/libraries/dirac { }; + + directfb = callPackage ../development/libraries/directfb { }; + + discord-rpc = callPackage ../development/libraries/discord-rpc { + inherit (darwin.apple_sdk.frameworks) AppKit; + }; + + dlib = callPackage ../development/libraries/dlib { }; + + docopt_cpp = callPackage ../development/libraries/docopt_cpp { }; + + dotconf = callPackage ../development/libraries/dotconf { }; + + # Multi-arch "drivers" which we want to build for i686. + driversi686Linux = recurseIntoAttrs { + inherit (pkgsi686Linux) + mesa + vaapiIntel + libvdpau-va-gl + vaapiVdpau + beignet + glxinfo + vdpauinfo; + }; + + dssi = callPackage ../development/libraries/dssi {}; + + dxflib = callPackage ../development/libraries/dxflib {}; + + easyloggingpp = callPackage ../development/libraries/easyloggingpp {}; + + eccodes = callPackage ../development/libraries/eccodes { }; + + eclib = callPackage ../development/libraries/eclib {}; + + editline = callPackage ../development/libraries/editline { }; + + eigen = callPackage ../development/libraries/eigen {}; + + eigen2 = callPackage ../development/libraries/eigen/2.0.nix {}; + + vmmlib = callPackage ../development/libraries/vmmlib { + inherit (darwin.apple_sdk.frameworks) Accelerate CoreGraphics CoreVideo; + }; + + elastix = callPackage ../development/libraries/science/biology/elastix { }; + + enchant1 = callPackage ../development/libraries/enchant/1.x.nix { }; + + enchant2 = callPackage ../development/libraries/enchant/2.x.nix { }; + enchant = enchant2; + + enet = callPackage ../development/libraries/enet { }; + + epoxy = callPackage ../development/libraries/epoxy {}; + + libesmtp = callPackage ../development/libraries/libesmtp { }; + + exiv2 = callPackage ../development/libraries/exiv2 { }; + + expat = callPackage ../development/libraries/expat { }; + + eventlog = callPackage ../development/libraries/eventlog { }; + + faac = callPackage ../development/libraries/faac { }; + + faad2 = callPackage ../development/libraries/faad2 { }; + + factor-lang = callPackage ../development/compilers/factor-lang { + inherit (pkgs.gnome2) gtkglext; + }; + + far2l = callPackage ../applications/misc/far2l { + stdenv = if stdenv.cc.isClang then llvmPackages_4.stdenv else stdenv; + }; + + farbfeld = callPackage ../development/libraries/farbfeld { }; + + farstream = callPackage ../development/libraries/farstream { + inherit (gst_all_1) + gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad + gst-libav; + inherit (pythonPackages) gst-python; + }; + + fcgi = callPackage ../development/libraries/fcgi { }; + + ffcast = callPackage ../tools/X11/ffcast { }; + + fflas-ffpack = callPackage ../development/libraries/fflas-ffpack { + # We need to use blas instead of openblas on darwin, + # see https://github.com/NixOS/nixpkgs/pull/45013. + blas = if stdenv.isDarwin then blas else openblas; + }; + + fflas-ffpack_1 = callPackage ../development/libraries/fflas-ffpack/1.nix {}; + linbox = callPackage ../development/libraries/linbox { + # We need to use blas instead of openblas on darwin, see + # https://github.com/NixOS/nixpkgs/pull/45013 and + # https://github.com/NixOS/nixpkgs/pull/45015. + blas = if stdenv.isDarwin then blas else openblas; + }; + + ffmpeg_2_8 = callPackage ../development/libraries/ffmpeg/2.8.nix { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + ffmpeg_3_4 = callPackage ../development/libraries/ffmpeg/3.4.nix { + inherit (darwin.apple_sdk.frameworks) Cocoa CoreMedia; + }; + ffmpeg_4 = callPackage ../development/libraries/ffmpeg/4.nix { + inherit (darwin.apple_sdk.frameworks) Cocoa CoreMedia VideoToolbox; + }; + + # Aliases + ffmpeg_2 = ffmpeg_2_8; + ffmpeg_3 = ffmpeg_3_4; + ffmpeg = ffmpeg_3; + + ffmpeg-full = callPackage ../development/libraries/ffmpeg-full { + # The following need to be fixed on Darwin + frei0r = if stdenv.isDarwin then null else frei0r; + game-music-emu = if stdenv.isDarwin then null else game-music-emu; + libjack2 = if stdenv.isDarwin then null else libjack2; + libmodplug = if stdenv.isDarwin then null else libmodplug; + openal = if stdenv.isDarwin then null else openal; + libmfx = if stdenv.isDarwin then null else intel-media-sdk; + libpulseaudio = if stdenv.isDarwin then null else libpulseaudio; + samba = if stdenv.isDarwin then null else samba; + vid-stab = if stdenv.isDarwin then null else vid-stab; + x265 = if stdenv.isDarwin then null else x265; + xavs = if stdenv.isDarwin then null else xavs; + inherit (darwin.apple_sdk.frameworks) + Cocoa CoreServices CoreAudio AVFoundation MediaToolbox + VideoDecodeAcceleration; + }; + + ffmpegthumbnailer = callPackage ../development/libraries/ffmpegthumbnailer { }; + + ffmpeg-sixel = callPackage ../development/libraries/ffmpeg-sixel { }; + + ffms = callPackage ../development/libraries/ffms { }; + + fftw = callPackage ../development/libraries/fftw { }; + fftwSinglePrec = fftw.override { precision = "single"; }; + fftwFloat = fftwSinglePrec; # the configure option is just an alias + fftwLongDouble = fftw.override { precision = "long-double"; }; + + filter-audio = callPackage ../development/libraries/filter-audio {}; + + flann = callPackage ../development/libraries/flann { }; + + flatcc = callPackage ../development/libraries/flatcc { }; + + flint = callPackage ../development/libraries/flint { }; + + flite = callPackage ../development/libraries/flite { }; + + fltk13 = callPackage ../development/libraries/fltk { + inherit (darwin.apple_sdk.frameworks) Cocoa AGL GLUT; + }; + fltk14 = callPackage ../development/libraries/fltk/1.4.nix { + inherit (darwin.apple_sdk.frameworks) Cocoa AGL GLUT; + }; + fltk = res.fltk13; + + flyway = callPackage ../development/tools/flyway { }; + + fmt = callPackage ../development/libraries/fmt/default.nix { }; + + fplll = callPackage ../development/libraries/fplll {}; + fplll_20160331 = callPackage ../development/libraries/fplll/20160331.nix {}; + + freeimage = callPackage ../development/libraries/freeimage { }; + + freetts = callPackage ../development/libraries/freetts { }; + + frog = res.languageMachines.frog; + + fstrcmp = callPackage ../development/libraries/fstrcmp { }; + + fstrm = callPackage ../development/libraries/fstrm { }; + + cfitsio = callPackage ../development/libraries/cfitsio { }; + + fontconfig_210 = callPackage ../development/libraries/fontconfig/2.10.nix { }; + + fontconfig = callPackage ../development/libraries/fontconfig { }; + + fontconfig-penultimate = callPackage ../data/fonts/fontconfig-penultimate {}; + + fontconfig-ultimate = callPackage ../development/libraries/fontconfig-ultimate {}; + + folly = callPackage ../development/libraries/folly { }; + + folks = callPackage ../development/libraries/folks { }; + + makeFontsConf = let fontconfig_ = fontconfig; in {fontconfig ? fontconfig_, fontDirectories}: + callPackage ../development/libraries/fontconfig/make-fonts-conf.nix { + inherit fontconfig fontDirectories; + }; + + makeFontsCache = let fontconfig_ = fontconfig; in {fontconfig ? fontconfig_, fontDirectories}: + callPackage ../development/libraries/fontconfig/make-fonts-cache.nix { + inherit fontconfig fontDirectories; + }; + + freealut = callPackage ../development/libraries/freealut { }; + + freeglut = callPackage ../development/libraries/freeglut { }; + + freenect = callPackage ../development/libraries/freenect { + inherit (darwin.apple_sdk.frameworks) Cocoa GLUT; + }; + + freetype = callPackage ../development/libraries/freetype { }; + + frei0r = callPackage ../development/libraries/frei0r { }; + + fribidi = callPackage ../development/libraries/fribidi { }; + + funambol = callPackage ../development/libraries/funambol { }; + + gamin = callPackage ../development/libraries/gamin { }; + fam = gamin; # added 2018-04-25 + + ganv = callPackage ../development/libraries/ganv { }; + + gcab = callPackage ../development/libraries/gcab { }; + + gcovr = with python3Packages; toPythonApplication gcovr; + + gcr = callPackage ../development/libraries/gcr { }; + + gdl = callPackage ../development/libraries/gdl { }; + + gdome2 = callPackage ../development/libraries/gdome2 { }; + + gdbm = callPackage ../development/libraries/gdbm { }; + + gecode_3 = callPackage ../development/libraries/gecode/3.nix { }; + gecode_6 = qt5.callPackage ../development/libraries/gecode { }; + gecode = gecode_6; + + gephi = callPackage ../applications/science/misc/gephi { }; + + gegl = callPackage ../development/libraries/gegl { + inherit (darwin.apple_sdk.frameworks) OpenGL; + }; + + gegl_0_3 = callPackage ../development/libraries/gegl/3.0.nix { + gtk = res.gtk2; + }; + + gegl_0_4 = callPackage ../development/libraries/gegl/4.0.nix { + gtk = res.gtk2; + }; + + geoclue2 = callPackage ../development/libraries/geoclue {}; + + geocode-glib = callPackage ../development/libraries/geocode-glib {}; + + geoipWithDatabase = makeOverridable (callPackage ../development/libraries/geoip) { + drvName = "geoip-tools"; + geoipDatabase = geolite-legacy; + }; + + geoip = callPackage ../development/libraries/geoip { }; + + geoipjava = callPackage ../development/libraries/java/geoipjava { }; + + geos = callPackage ../development/libraries/geos { }; + + getdata = callPackage ../development/libraries/getdata { }; + + getdns = callPackage ../development/libraries/getdns { }; + + gettext = callPackage ../development/libraries/gettext { }; + + gf2x = callPackage ../development/libraries/gf2x {}; + + gd = callPackage ../development/libraries/gd { + libtiff = null; + libXpm = null; + }; + + gdal = callPackage ../development/libraries/gdal { }; + + gdal_1_11 = callPackage ../development/libraries/gdal/gdal-1_11.nix { }; + + gdal_2 = callPackage ../development/libraries/gdal/2.4.0.nix { }; + + gdcm = callPackage ../development/libraries/gdcm { }; + + ggz_base_libs = callPackage ../development/libraries/ggz_base_libs {}; + + giblib = callPackage ../development/libraries/giblib { }; + + gio-sharp = callPackage ../development/libraries/gio-sharp { }; + + givaro = callPackage ../development/libraries/givaro {}; + givaro_3 = callPackage ../development/libraries/givaro/3.nix {}; + givaro_3_7 = callPackage ../development/libraries/givaro/3.7.nix {}; + + ghp-import = callPackage ../development/tools/ghp-import { }; + + ghcid = haskellPackages.ghcid.bin; + + icon-lang = callPackage ../development/interpreters/icon-lang { }; + + libgit2 = callPackage ../development/libraries/git2 { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + libgit2-glib = callPackage ../development/libraries/libgit2-glib { }; + + glbinding = callPackage ../development/libraries/glbinding { }; + + gle = callPackage ../development/libraries/gle { }; + + glew = callPackage ../development/libraries/glew { }; + glew110 = callPackage ../development/libraries/glew/1.10.nix { + inherit (darwin.apple_sdk.frameworks) AGL; + }; + + glfw = glfw3; + glfw2 = callPackage ../development/libraries/glfw/2.x.nix { }; + glfw3 = callPackage ../development/libraries/glfw/3.x.nix { + inherit (darwin.apple_sdk.frameworks) Cocoa Kernel; + }; + + glibc = callPackage ../development/libraries/glibc { }; + + # Provided by libc on Operating Systems that use the Extensible Linker Format. + elf-header = + if stdenv.hostPlatform.parsed.kernel.execFormat.name == "elf" + then null + else elf-header-real; + + elf-header-real = callPackage ../development/libraries/elf-header { }; + + glibc_memusage = callPackage ../development/libraries/glibc { + withGd = true; + }; + + # Being redundant to avoid cycles on boot. TODO: find a better way + glibcCross = callPackage ../development/libraries/glibc { + stdenv = crossLibcStdenv; + }; + + muslCross = musl.override { + stdenv = crossLibcStdenv; + }; + + # We can choose: + libcCrossChooser = name: + # libc is hackily often used from the previous stage. This `or` + # hack fixes the hack, *sigh*. + /**/ if name == "glibc" then targetPackages.glibcCross or glibcCross + else if name == "bionic" then targetPackages.bionic or bionic + else if name == "uclibc" then targetPackages.uclibcCross or uclibcCross + else if name == "avrlibc" then targetPackages.avrlibcCross or avrlibcCross + else if name == "newlib" && stdenv.targetPlatform.isMsp430 then targetPackages.msp430NewlibCross or msp430NewlibCross + else if name == "newlib" then targetPackages.newlibCross or newlibCross + else if name == "musl" then targetPackages.muslCross or muslCross + else if name == "msvcrt" then targetPackages.windows.mingw_w64 or windows.mingw_w64 + else if stdenv.targetPlatform.useiOSPrebuilt then targetPackages.darwin.iosSdkPkgs.libraries or darwin.iosSdkPkgs.libraries + else if name == "libSystem" then targetPackages.darwin.xcode + else if name == "nblibc" then targetPackages.netbsdCross.libc + else if name == "wasilibc" then targetPackages.wasilibc or wasilibc + else throw "Unknown libc ${name}"; + + libcCross = assert stdenv.targetPlatform != stdenv.buildPlatform; libcCrossChooser stdenv.targetPlatform.libc; + + wasilibc = callPackage ../development/libraries/wasilibc { + stdenv = crossLibcStdenv; + }; + + # Only supported on Linux, using glibc + glibcLocales = if stdenv.hostPlatform.libc == "glibc" then callPackage ../development/libraries/glibc/locales.nix { } else null; + + glibcInfo = callPackage ../development/libraries/glibc/info.nix { }; + + glibc_multi = callPackage ../development/libraries/glibc/multi.nix { + glibc32 = pkgsi686Linux.glibc; + }; + + glm = callPackage ../development/libraries/glm { }; + + globalplatform = callPackage ../development/libraries/globalplatform { }; + gppcscconnectionplugin = + callPackage ../development/libraries/globalplatform/gppcscconnectionplugin.nix { }; + + glog = callPackage ../development/libraries/glog { }; + + gloox = callPackage ../development/libraries/gloox { }; + + glpk = callPackage ../development/libraries/glpk { }; + + glsurf = callPackage ../applications/science/math/glsurf { + libpng = libpng12; + giflib = giflib_4_1; + ocamlPackages = ocaml-ng.ocamlPackages_4_01_0; + }; + + glui = callPackage ../development/libraries/glui {}; + + gmime2 = callPackage ../development/libraries/gmime/2.nix { }; + gmime3 = callPackage ../development/libraries/gmime/3.nix { }; + gmime = gmime2; + + gmm = callPackage ../development/libraries/gmm { }; + + gmp4 = callPackage ../development/libraries/gmp/4.3.2.nix { }; # required by older GHC versions + gmp5 = callPackage ../development/libraries/gmp/5.1.x.nix { }; + gmp6 = callPackage ../development/libraries/gmp/6.x.nix { }; + gmp = gmp6; + gmpxx = appendToName "with-cxx" (gmp.override { cxx = true; }); + + #GMP ex-satellite, so better keep it near gmp + mpfr = callPackage ../development/libraries/mpfr { }; + + mpfi = callPackage ../development/libraries/mpfi { }; + + mpfshell = callPackage ../development/tools/mpfshell { }; + + # A GMP fork + mpir = callPackage ../development/libraries/mpir {}; + + gns3Packages = dontRecurseIntoAttrs (callPackage ../applications/networking/gns3 { }); + gns3-gui = gns3Packages.guiStable; + gns3-server = gns3Packages.serverStable; + + gobject-introspection = callPackage ../development/libraries/gobject-introspection { + nixStoreDir = config.nix.storeDir or builtins.storeDir; + inherit (darwin) cctools; + }; + + goocanvas = callPackage ../development/libraries/goocanvas { }; + goocanvas2 = callPackage ../development/libraries/goocanvas/2.x.nix { }; + goocanvasmm2 = callPackage ../development/libraries/goocanvasmm { }; + + gflags = callPackage ../development/libraries/gflags { }; + + gperftools = callPackage ../development/libraries/gperftools { }; + + grab-site = callPackage ../tools/backup/grab-site { }; + + grib-api = callPackage ../development/libraries/grib-api { }; + + grilo = callPackage ../development/libraries/grilo { }; + + grilo-plugins = callPackage ../development/libraries/grilo-plugins { }; + + grpc = callPackage ../development/libraries/grpc { }; + + gsettings-qt = libsForQt5.callPackage ../development/libraries/gsettings-qt { }; + + gst_all_1 = recurseIntoAttrs(callPackage ../development/libraries/gstreamer { + callPackage = newScope { libav = pkgs.ffmpeg_4; }; + inherit (darwin.apple_sdk.frameworks) CoreServices; + }); + + gstreamer = callPackage ../development/libraries/gstreamer/legacy/gstreamer { }; + + gst-plugins-base = callPackage ../development/libraries/gstreamer/legacy/gst-plugins-base { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + }; + + gst-plugins-good = callPackage ../development/libraries/gstreamer/legacy/gst-plugins-good {}; + + gst-plugins-bad = callPackage ../development/libraries/gstreamer/legacy/gst-plugins-bad {}; + + gst-plugins-ugly = callPackage ../development/libraries/gstreamer/legacy/gst-plugins-ugly {}; + + gst-python = callPackage ../development/libraries/gstreamer/legacy/gst-python {}; + + gstreamermm = callPackage ../development/libraries/gstreamer/legacy/gstreamermm { }; + + gnonlin = callPackage ../development/libraries/gstreamer/legacy/gnonlin {}; + + gusb = callPackage ../development/libraries/gusb { }; + + qt-mobility = callPackage ../development/libraries/qt-mobility {}; + + qt-gstreamer = callPackage ../development/libraries/gstreamer/legacy/qt-gstreamer {}; + + qt-gstreamer1 = callPackage ../development/libraries/gstreamer/qt-gstreamer { boost = boost155; }; + + qtstyleplugin-kvantum-qt4 = callPackage ../development/libraries/qtstyleplugin-kvantum-qt4 { }; + + gnet = callPackage ../development/libraries/gnet { }; + + gnu-config = callPackage ../development/libraries/gnu-config { }; + + gnu-efi = if stdenv.hostPlatform.isEfi + then callPackage ../development/libraries/gnu-efi { } + else null; + + gnutls = callPackage ../development/libraries/gnutls/default.nix { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + gnutls-kdh = callPackage ../development/libraries/gnutls-kdh/3.5.nix { + gperf = gperf_3_0; + }; + + gpac = callPackage ../applications/video/gpac { }; + + gpgme = callPackage ../development/libraries/gpgme { }; + + pgpdump = callPackage ../tools/security/pgpdump { }; + + pgpkeyserver-lite = callPackage ../servers/web-apps/pgpkeyserver-lite {}; + + gpgstats = callPackage ../tools/security/gpgstats { }; + + gpshell = callPackage ../development/tools/misc/gpshell { }; + + grantlee = callPackage ../development/libraries/grantlee { }; + + gsasl = callPackage ../development/libraries/gsasl { }; + + gsl = callPackage ../development/libraries/gsl { }; + + gsl_1 = callPackage ../development/libraries/gsl/gsl-1_16.nix { }; + + gsm = callPackage ../development/libraries/gsm {}; + + gsoap = callPackage ../development/libraries/gsoap { }; + + gsound = callPackage ../development/libraries/gsound { }; + + gss = callPackage ../development/libraries/gss { }; + + gtkimageview = callPackage ../development/libraries/gtkimageview { }; + + gtkmathview = callPackage ../development/libraries/gtkmathview { }; + + glib = callPackage ../development/libraries/glib (let + glib-untested = glib.override { doCheck = false; }; + in { + # break dependency cycles + # these things are only used for tests, they don't get into the closure + shared-mime-info = shared-mime-info.override { glib = glib-untested; }; + desktop-file-utils = desktop-file-utils.override { glib = glib-untested; }; + dbus = dbus.override { systemd = null; }; + }); + + glibmm = callPackage ../development/libraries/glibmm { }; + + glib-networking = callPackage ../development/libraries/glib-networking {}; + + gom = callPackage ../development/libraries/gom { }; + + ace = callPackage ../development/libraries/ace { }; + + atk = callPackage ../development/libraries/atk { }; + + atkmm = callPackage ../development/libraries/atkmm { }; + + pixman = callPackage ../development/libraries/pixman { }; + + cairo = callPackage ../development/libraries/cairo { }; + + cairomm = callPackage ../development/libraries/cairomm { }; + + pango = callPackage ../development/libraries/pango { }; + + pangolin = callPackage ../development/libraries/pangolin { + inherit (darwin.apple_sdk.frameworks) Carbon Cocoa; + }; + + pangomm = callPackage ../development/libraries/pangomm { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + }; + + pangox_compat = callPackage ../development/libraries/pangox-compat { }; + + gdata-sharp = callPackage ../development/libraries/gdata-sharp { }; + + gdk-pixbuf = callPackage ../development/libraries/gdk-pixbuf { }; + + gnome-sharp = callPackage ../development/libraries/gnome-sharp { }; + + gnome-menus = callPackage ../development/libraries/gnome-menus { }; + + elementary-cmake-modules = callPackage ../development/libraries/elementary-cmake-modules { }; + + gtk2 = callPackage ../development/libraries/gtk+/2.x.nix { + inherit (darwin.apple_sdk.frameworks) AppKit Cocoa; + }; + + gtk2-x11 = gtk2.override { + cairo = cairo.override { x11Support = true; }; + pango = pango.override { cairo = cairo.override { x11Support = true; }; x11Support = true; }; + gdktarget = "x11"; + }; + + gtk3 = callPackage ../development/libraries/gtk+/3.x.nix { + inherit (darwin.apple_sdk.frameworks) AppKit Cocoa; + }; + + # On darwin gtk uses cocoa by default instead of x11. + gtk3-x11 = gtk3.override { + cairo = cairo.override { x11Support = true; }; + pango = pango.override { cairo = cairo.override { x11Support = true; }; x11Support = true; }; + x11Support = true; + }; + + gtkmm2 = callPackage ../development/libraries/gtkmm/2.x.nix { }; + gtkmm3 = callPackage ../development/libraries/gtkmm/3.x.nix { }; + + gtk-sharp-2_0 = callPackage ../development/libraries/gtk-sharp/2.0.nix { + inherit (gnome2) libglade libgtkhtml gtkhtml + libgnomecanvas libgnomeui libgnomeprint + libgnomeprintui GConf; + }; + + gtk-sharp-3_0 = callPackage ../development/libraries/gtk-sharp/3.0.nix { + inherit (gnome2) libglade libgtkhtml gtkhtml + libgnomecanvas libgnomeui libgnomeprint + libgnomeprintui GConf; + }; + + gtk-sharp-beans = callPackage ../development/libraries/gtk-sharp-beans { }; + + gtk-mac-integration = callPackage ../development/libraries/gtk-mac-integration { + gtk = gtk3; + }; + + gtk-mac-integration-gtk2 = gtk-mac-integration.override { + gtk = gtk2; + }; + + gtk-mac-integration-gtk3 = gtk-mac-integration; + + gtk-mac-bundler = callPackage ../development/tools/gtk-mac-bundler {}; + + gtksourceview = gtksourceview3; + + gtksourceview3 = callPackage ../development/libraries/gtksourceview/3.x.nix { }; + + gtksourceview4 = callPackage ../development/libraries/gtksourceview/4.x.nix { }; + + gtksourceviewmm = callPackage ../development/libraries/gtksourceviewmm { }; + + gtksourceviewmm4 = callPackage ../development/libraries/gtksourceviewmm/4.x.nix { }; + + gtkspell2 = callPackage ../development/libraries/gtkspell { enchant = enchant1; }; + + gtkspell3 = callPackage ../development/libraries/gtkspell/3.nix { }; + + gtkspellmm = callPackage ../development/libraries/gtkspellmm { }; + + gts = callPackage ../development/libraries/gts { }; + + gumbo = callPackage ../development/libraries/gumbo { }; + + gvfs = callPackage ../development/libraries/gvfs { + gnome = res.gnome3; + }; + + gwenhywfar = callPackage ../development/libraries/aqbanking/gwenhywfar.nix { }; + + hamlib = callPackage ../development/libraries/hamlib { }; + + heimdal = callPackage ../development/libraries/kerberos/heimdal.nix { + inherit (darwin.apple_sdk.frameworks) CoreFoundation Security SystemConfiguration; + }; + libheimdal = heimdal; + + harfbuzz = callPackage ../development/libraries/harfbuzz { + inherit (darwin.apple_sdk.frameworks) ApplicationServices CoreText; + }; + + harfbuzzFull = harfbuzz.override { + withCoreText = stdenv.isDarwin; + withGraphite2 = true; + withIcu = true; + }; + + hawknl = callPackage ../development/libraries/hawknl { }; + + haxor-news = callPackage ../applications/misc/haxor-news { }; + + herqq = libsForQt5.callPackage ../development/libraries/herqq { }; + + heyefi = haskellPackages.heyefi; + + hidapi = callPackage ../development/libraries/hidapi { + libusb = libusb1; + }; + + hiredis = callPackage ../development/libraries/hiredis { }; + + hiredis-vip = callPackage ../development/libraries/hiredis-vip { }; + + hivex = callPackage ../development/libraries/hivex { }; + + hound = callPackage ../development/tools/misc/hound { }; + + hpx = callPackage ../development/libraries/hpx { }; + + hspell = callPackage ../development/libraries/hspell { }; + + hspellDicts = callPackage ../development/libraries/hspell/dicts.nix { }; + + hsqldb = callPackage ../development/libraries/java/hsqldb { }; + + hstr = callPackage ../applications/misc/hstr { }; + + htmlcxx = callPackage ../development/libraries/htmlcxx { }; + + http-parser = callPackage ../development/libraries/http-parser { }; + + hunspell = callPackage ../development/libraries/hunspell { }; + + hunspellDicts = recurseIntoAttrs (callPackages ../development/libraries/hunspell/dictionaries.nix {}); + + hunspellWithDicts = dicts: callPackage ../development/libraries/hunspell/wrapper.nix { inherit dicts; }; + + hwloc = callPackage ../development/libraries/hwloc {}; + + hydra = callPackage ../development/tools/misc/hydra { }; + + hydraAntLogger = callPackage ../development/libraries/java/hydra-ant-logger { }; + + hyena = callPackage ../development/libraries/hyena { }; + + hyperscan = callPackage ../development/libraries/hyperscan { }; + + icu58 = callPackage (import ../development/libraries/icu/58.nix fetchurl) ({ + nativeBuildRoot = buildPackages.icu58.override { buildRootOnly = true; }; + } // + (stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + })); + icu59 = callPackage ../development/libraries/icu/59.nix ({ + nativeBuildRoot = buildPackages.icu59.override { buildRootOnly = true; }; + } // (stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + })); + icu60 = callPackage ../development/libraries/icu/60.nix ({ + nativeBuildRoot = buildPackages.icu60.override { buildRootOnly = true; }; + } // (stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + })); + icu63 = callPackage ../development/libraries/icu/63.nix ({ + nativeBuildRoot = buildPackages.icu63.override { buildRootOnly = true; }; + } // (stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + })); + icu64 = callPackage ../development/libraries/icu/64.nix ({ + nativeBuildRoot = buildPackages.icu64.override { buildRootOnly = true; }; + } // (stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = gcc6Stdenv; # with gcc-7: undefined reference to `__divmoddi4' + })); + + icu = icu64; + + id3lib = callPackage ../development/libraries/id3lib { }; + + ilbc = callPackage ../development/libraries/ilbc { }; + + ilixi = callPackage ../development/libraries/ilixi { }; + + ilmbase = callPackage ../development/libraries/ilmbase { }; + + intelmetool = callPackage ../tools/misc/intelmetool { }; + + imlib = callPackage ../development/libraries/imlib { + libpng = libpng12; + }; + + imv = callPackage ../applications/graphics/imv { }; + + iml = callPackage ../development/libraries/iml { }; + + imlib2 = callPackage ../development/libraries/imlib2 { }; + imlib2-nox = imlib2.override { + x11Support = false; + }; + + imlibsetroot = callPackage ../applications/graphics/imlibsetroot { libXinerama = xorg.libXinerama; } ; + + ineffassign = callPackage ../development/tools/ineffassign { }; + + ijs = callPackage ../development/libraries/ijs { }; + + incrtcl = callPackage ../development/libraries/incrtcl { }; + + indicator-application-gtk2 = callPackage ../development/libraries/indicator-application/gtk2.nix { }; + indicator-application-gtk3 = callPackage ../development/libraries/indicator-application/gtk3.nix { }; + + indilib = callPackage ../development/libraries/indilib { }; + + iniparser = callPackage ../development/libraries/iniparser { }; + + intel-gmmlib = callPackage ../development/libraries/intel-gmmlib { }; + + intel-media-driver = callPackage ../development/libraries/intel-media-driver { }; + + intltool = callPackage ../development/tools/misc/intltool { }; + + ios-cross-compile = callPackage ../development/compilers/ios-cross-compile/9.2.nix {}; + + ip2location-c = callPackage ../development/libraries/ip2location-c { }; + + irrlicht = callPackage ../development/libraries/irrlicht { }; + + isocodes = callPackage ../development/libraries/iso-codes { }; + + ispc = callPackage ../development/compilers/ispc { + llvmPackages = llvmPackages_6; + stdenv = llvmPackages_6.stdenv; + }; + + isso = callPackage ../servers/isso { }; + + itk = callPackage ../development/libraries/itk { }; + + jasper = callPackage ../development/libraries/jasper { }; + + jama = callPackage ../development/libraries/jama { }; + + jansson = callPackage ../development/libraries/jansson { }; + + jbig2dec = callPackage ../development/libraries/jbig2dec { }; + + jcal = callPackage ../development/libraries/jcal { }; + + jbigkit = callPackage ../development/libraries/jbigkit { }; + + jemalloc = callPackage ../development/libraries/jemalloc { }; + + jemalloc450 = callPackage ../development/libraries/jemalloc/jemalloc450.nix { }; + + jshon = callPackage ../development/tools/parsing/jshon { }; + + json2hcl = callPackage ../development/tools/json2hcl { }; + + json-glib = callPackage ../development/libraries/json-glib { }; + + json_c = callPackage ../development/libraries/json-c { }; + + jsoncpp = callPackage ../development/libraries/jsoncpp { }; + + jsonnet = callPackage ../development/compilers/jsonnet { }; + + go-jsonnet = callPackage ../development/compilers/go-jsonnet { }; + + jsonrpc-glib = callPackage ../development/libraries/jsonrpc-glib { }; + + jxrlib = callPackage ../development/libraries/jxrlib { }; + + libjson = callPackage ../development/libraries/libjson { }; + + libb64 = callPackage ../development/libraries/libb64 { }; + + judy = callPackage ../development/libraries/judy { }; + + kdeFrameworks = + let + mkFrameworks = import ../development/libraries/kde-frameworks; + attrs = { + inherit libsForQt5; + inherit lib fetchurl; + }; + in + recurseIntoAttrs (makeOverridable mkFrameworks attrs); + + keybinder = callPackage ../development/libraries/keybinder { + automake = automake111x; + lua = lua5_1; + }; + + keybinder3 = callPackage ../development/libraries/keybinder3 { + automake = automake111x; + }; + + kinetic-cpp-client = callPackage ../development/libraries/kinetic-cpp-client { }; + + krb5 = callPackage ../development/libraries/kerberos/krb5.nix { + inherit (buildPackages.darwin) bootstrap_cmds; + }; + krb5Full = krb5; + libkrb5 = krb5.override { type = "lib"; }; + kerberos = libkrb5; # TODO: move to aliases.nix + + l-smash = callPackage ../development/libraries/l-smash { + stdenv = gccStdenv; + }; + + languageMachines = recurseIntoAttrs (import ../development/libraries/languagemachines/packages.nix { + inherit pkgs; + }); + + lasem = callPackage ../development/libraries/lasem { }; + + lasso = callPackage ../development/libraries/lasso { }; + + LASzip = callPackage ../development/libraries/LASzip { }; + + lcms = lcms1; + + lcms1 = callPackage ../development/libraries/lcms { }; + + lcms2 = callPackage ../development/libraries/lcms2 { }; + + ldacbt = callPackage ../development/libraries/ldacbt { }; + + ldb = callPackage ../development/libraries/ldb { + python = python2; + }; + + lensfun = callPackage ../development/libraries/lensfun {}; + + lesstif = callPackage ../development/libraries/lesstif { }; + + leveldb = callPackage ../development/libraries/leveldb { }; + + lmdb = callPackage ../development/libraries/lmdb { }; + + lmdbxx = callPackage ../development/libraries/lmdbxx { }; + + levmar = callPackage ../development/libraries/levmar { }; + + leptonica = callPackage ../development/libraries/leptonica { }; + + lib3ds = callPackage ../development/libraries/lib3ds { }; + + lib3mf = callPackage ../development/libraries/lib3mf { }; + + libaacs = callPackage ../development/libraries/libaacs { }; + + libaal = callPackage ../development/libraries/libaal { }; + + libaccounts-glib = callPackage ../development/libraries/libaccounts-glib { }; + + libacr38u = callPackage ../tools/security/libacr38u { }; + + libagar = callPackage ../development/libraries/libagar { }; + libagar_test = callPackage ../development/libraries/libagar/libagar_test.nix { }; + + libao = callPackage ../development/libraries/libao { + usePulseAudio = config.pulseaudio or stdenv.isLinux; + inherit (darwin.apple_sdk.frameworks) CoreAudio CoreServices AudioUnit; + }; + + libaosd = callPackage ../development/libraries/libaosd { }; + + libabw = callPackage ../development/libraries/libabw { }; + + libamqpcpp = callPackage ../development/libraries/libamqpcpp { }; + + libantlr3c = callPackage ../development/libraries/libantlr3c {}; + + libaom = callPackage ../development/libraries/libaom { }; + + libappindicator-gtk2 = libappindicator.override { gtkVersion = "2"; }; + libappindicator-gtk3 = libappindicator.override { gtkVersion = "3"; }; + libappindicator = callPackage ../development/libraries/libappindicator { }; + + libarchive = callPackage ../development/libraries/libarchive { }; + + libasr = callPackage ../development/libraries/libasr { }; + + libass = callPackage ../development/libraries/libass { }; + + libast = callPackage ../development/libraries/libast { }; + + libassuan = callPackage ../development/libraries/libassuan { }; + + libasyncns = callPackage ../development/libraries/libasyncns { }; + + libatomic_ops = callPackage ../development/libraries/libatomic_ops {}; + + libaudclient = callPackage ../development/libraries/libaudclient { }; + + libav = libav_11; # branch 11 is API-compatible with branch 10 + libav_all = callPackage ../development/libraries/libav { }; + inherit (libav_all) libav_0_8 libav_11 libav_12; + + libavc1394 = callPackage ../development/libraries/libavc1394 { }; + + libb2 = callPackage ../development/libraries/libb2 { }; + + libbap = callPackage ../development/libraries/libbap { + inherit (ocamlPackages) bap ocaml findlib ctypes; + }; + + libbass = (callPackage ../development/libraries/audio/libbass { }).bass; + libbass_fx = (callPackage ../development/libraries/audio/libbass { }).bass_fx; + + libbluedevil = callPackage ../development/libraries/libbluedevil { }; + + libbdplus = callPackage ../development/libraries/libbdplus { }; + + libblockdev = callPackage ../development/libraries/libblockdev { }; + + libblocksruntime = callPackage ../development/libraries/libblocksruntime { }; + + libbluray = callPackage ../development/libraries/libbluray { }; + + libbs2b = callPackage ../development/libraries/audio/libbs2b { }; + + libbson = callPackage ../development/libraries/libbson { }; + + libburn = callPackage ../development/libraries/libburn { }; + + libbytesize = callPackage ../development/libraries/libbytesize { }; + + libcaca = callPackage ../development/libraries/libcaca { + inherit (xorg) libX11 libXext; + }; + + libcacard = callPackage ../development/libraries/libcacard { }; + + libcanberra = callPackage ../development/libraries/libcanberra { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + libcanberra-gtk3 = pkgs.libcanberra.override { + gtk = gtk3.override { x11Support = true; }; + }; + libcanberra-gtk2 = pkgs.libcanberra-gtk3.override { + gtk = gtk2.override { gdktarget = "x11"; }; + }; + + libcanberra_kde = if (config.kde_runtime.libcanberraWithoutGTK or true) + then pkgs.libcanberra + else pkgs.libcanberra-gtk2; + + libcbor = callPackage ../development/libraries/libcbor { }; + + libcec = callPackage ../development/libraries/libcec { }; + libcec_platform = callPackage ../development/libraries/libcec/platform.nix { }; + + libcef = callPackage ../development/libraries/libcef { inherit (gnome2) GConf; }; + + libcello = callPackage ../development/libraries/libcello {}; + + libcerf = callPackage ../development/libraries/libcerf {}; + + libcdaudio = callPackage ../development/libraries/libcdaudio { }; + + libcddb = callPackage ../development/libraries/libcddb { }; + + libcdio = callPackage ../development/libraries/libcdio { + inherit (darwin.apple_sdk.frameworks) Carbon IOKit; + }; + + libcdio-paranoia = callPackage ../development/libraries/libcdio-paranoia { + inherit (darwin.apple_sdk.frameworks) DiskArbitration IOKit; + }; + + libcdr = callPackage ../development/libraries/libcdr { lcms = lcms2; }; + + libchamplain = callPackage ../development/libraries/libchamplain { }; + + libchardet = callPackage ../development/libraries/libchardet { }; + + libchewing = callPackage ../development/libraries/libchewing { }; + + libchipcard = callPackage ../development/libraries/aqbanking/libchipcard.nix { }; + + libcrafter = callPackage ../development/libraries/libcrafter { }; + + libcrossguid = callPackage ../development/libraries/libcrossguid { }; + + libuchardet = callPackage ../development/libraries/libuchardet { }; + + libchop = callPackage ../development/libraries/libchop { }; + + libclc = callPackage ../development/libraries/libclc { }; + + libcli = callPackage ../development/libraries/libcli { }; + + libclthreads = callPackage ../development/libraries/libclthreads { }; + + libclxclient = callPackage ../development/libraries/libclxclient { }; + + libconfuse = callPackage ../development/libraries/libconfuse { }; + + libcangjie = callPackage ../development/libraries/libcangjie { }; + + libcollectdclient = callPackage ../development/libraries/libcollectdclient { }; + + libcredis = callPackage ../development/libraries/libcredis { }; + + libctemplate = callPackage ../development/libraries/libctemplate { }; + + libcouchbase = callPackage ../development/libraries/libcouchbase { }; + + libcue = callPackage ../development/libraries/libcue { }; + + libcutl = callPackage ../development/libraries/libcutl { }; + + libdaemon = callPackage ../development/libraries/libdaemon { }; + + libdap = callPackage ../development/libraries/libdap { }; + + libdazzle = callPackage ../development/libraries/libdazzle { }; + + libdbi = callPackage ../development/libraries/libdbi { }; + + libdbiDriversBase = libdbiDrivers.override { + mysql = null; + sqlite = null; + }; + + libdbiDrivers = callPackage ../development/libraries/libdbi-drivers { }; + + libunity = callPackage ../development/libraries/libunity { }; + + libdbusmenu = callPackage ../development/libraries/libdbusmenu { }; + libdbusmenu-gtk2 = libdbusmenu.override { gtkVersion = "2"; }; + libdbusmenu-gtk3 = libdbusmenu.override { gtkVersion = "3"; }; + + libdbusmenu_qt = callPackage ../development/libraries/libdbusmenu-qt { }; + + libdc1394 = callPackage ../development/libraries/libdc1394 { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + libde265 = callPackage ../development/libraries/libde265 {}; + + libdeflate = callPackage ../development/libraries/libdeflate { }; + + libdevil = callPackage ../development/libraries/libdevil { + inherit (darwin.apple_sdk.frameworks) OpenGL; + }; + + libdevil-nox = libdevil.override { + libX11 = null; + libGL = null; + }; + + libdigidoc = callPackage ../development/libraries/libdigidoc { }; + + libdigidocpp = callPackage ../development/libraries/libdigidocpp { }; + + libdiscid = callPackage ../development/libraries/libdiscid { }; + + libdivecomputer = callPackage ../development/libraries/libdivecomputer { }; + + libdivsufsort = callPackage ../development/libraries/libdivsufsort { }; + + libdmtx = callPackage ../development/libraries/libdmtx { }; + + libdnet = callPackage ../development/libraries/libdnet { }; + + libdrm = callPackage ../development/libraries/libdrm { }; + + libdv = callPackage ../development/libraries/libdv { }; + + libdvbpsi = callPackage ../development/libraries/libdvbpsi { }; + + libdwg = callPackage ../development/libraries/libdwg { }; + + libdvdcss = callPackage ../development/libraries/libdvdcss { + inherit (darwin) IOKit; + }; + + libdvdnav = callPackage ../development/libraries/libdvdnav { }; + libdvdnav_4_2_1 = callPackage ../development/libraries/libdvdnav/4.2.1.nix { + libdvdread = libdvdread_4_9_9; + }; + + libdvdread = callPackage ../development/libraries/libdvdread { }; + libdvdread_4_9_9 = callPackage ../development/libraries/libdvdread/4.9.9.nix { }; + + inherit (callPackage ../development/libraries/libdwarf { }) + libdwarf dwarfdump; + + libeatmydata = callPackage ../development/libraries/libeatmydata { }; + + libeb = callPackage ../development/libraries/libeb { }; + + libebml = callPackage ../development/libraries/libebml { }; + + libebur128 = callPackage ../development/libraries/libebur128 { }; + + libedit = callPackage ../development/libraries/libedit { }; + + libelf = if stdenv.isFreeBSD + then callPackage ../development/libraries/libelf-freebsd { } + else callPackage ../development/libraries/libelf { }; + + libelfin = callPackage ../development/libraries/libelfin { }; + + libetpan = callPackage ../development/libraries/libetpan { }; + + libexecinfo = callPackage ../development/libraries/libexecinfo { }; + + libfaketime = callPackage ../development/libraries/libfaketime { }; + + libfakekey = callPackage ../development/libraries/libfakekey { }; + + libfido2 = callPackage ../development/libraries/libfido2 { }; + + libfilezilla = callPackage ../development/libraries/libfilezilla { }; + + libfm = callPackage ../development/libraries/libfm { }; + libfm-extra = libfm.override { + extraOnly = true; + }; + + libfprint = callPackage ../development/libraries/libfprint { }; + libfprint-thinkpad = libfprint.override { + thinkpad = true; + }; + + libfpx = callPackage ../development/libraries/libfpx { }; + + libgadu = callPackage ../development/libraries/libgadu { }; + + libgda = callPackage ../development/libraries/libgda { }; + + libgdamm = callPackage ../development/libraries/libgdamm { }; + + libgdata = callPackage ../development/libraries/libgdata { }; + + libgee = callPackage ../development/libraries/libgee { }; + + libgepub = callPackage ../development/libraries/libgepub { }; + + libgig = callPackage ../development/libraries/libgig { }; + + libgnome-keyring = callPackage ../development/libraries/libgnome-keyring { }; + libgnome-keyring3 = gnome3.libgnome-keyring; + + libgnomekbd = callPackage ../development/libraries/libgnomekbd { }; + + libglvnd = callPackage ../development/libraries/libglvnd { }; + + libgnurl = callPackage ../development/libraries/libgnurl { }; + + libgringotts = callPackage ../development/libraries/libgringotts { }; + + libgroove = callPackage ../development/libraries/libgroove { }; + + libgrss = callPackage ../development/libraries/libgrss { }; + + libgweather = callPackage ../development/libraries/libgweather { }; + + libgxps = callPackage ../development/libraries/libgxps { }; + + libiio = callPackage ../development/libraries/libiio { }; + + liburing = callPackage ../development/libraries/liburing { }; + + libseccomp = callPackage ../development/libraries/libseccomp { }; + + libsecret = callPackage ../development/libraries/libsecret { }; + + libserialport = callPackage ../development/libraries/libserialport { }; + + libsignal-protocol-c = callPackage ../development/libraries/libsignal-protocol-c { }; + + libsignon-glib = callPackage ../development/libraries/libsignon-glib { }; + + libsoundio = callPackage ../development/libraries/libsoundio { + inherit (darwin.apple_sdk.frameworks) AudioUnit; + }; + + libsystemtap = callPackage ../development/libraries/libsystemtap { }; + + libgtop = callPackage ../development/libraries/libgtop {}; + + libLAS = callPackage ../development/libraries/libLAS { }; + + liblaxjson = callPackage ../development/libraries/liblaxjson { }; + + liblo = callPackage ../development/libraries/liblo { }; + + liblscp = callPackage ../development/libraries/liblscp { }; + + libe-book = callPackage ../development/libraries/libe-book {}; + + libechonest = callPackage ../development/libraries/libechonest { }; + + libev = callPackage ../development/libraries/libev { }; + + libevent = callPackage ../development/libraries/libevent { }; + + libewf = callPackage ../development/libraries/libewf { }; + + libexif = callPackage ../development/libraries/libexif { }; + + libexosip = callPackage ../development/libraries/exosip {}; + + libextractor = callPackage ../development/libraries/libextractor { + libmpeg2 = mpeg2dec; + }; + + libexttextcat = callPackage ../development/libraries/libexttextcat {}; + + libf2c = callPackage ../development/libraries/libf2c {}; + + libfive = callPackage ../development/libraries/libfive { }; + + libfixposix = callPackage ../development/libraries/libfixposix {}; + + libffcall = callPackage ../development/libraries/libffcall { }; + + libffi = callPackage ../development/libraries/libffi { }; + + libfreefare = callPackage ../development/libraries/libfreefare { + inherit (darwin) libobjc; + }; + + libftdi = callPackage ../development/libraries/libftdi { }; + + libftdi1 = callPackage ../development/libraries/libftdi/1.x.nix { }; + + libgcrypt = callPackage ../development/libraries/libgcrypt { }; + + libgcrypt_1_5 = callPackage ../development/libraries/libgcrypt/1.5.nix { }; + + libgdiplus = callPackage ../development/libraries/libgdiplus { + inherit (darwin.apple_sdk.frameworks) Carbon; + }; + + libgksu = callPackage ../development/libraries/libgksu { }; + + libgpgerror = callPackage ../development/libraries/libgpg-error { }; + + # https://github.com/gpg/libgpg-error/blob/70058cd9f944d620764e57c838209afae8a58c78/README#L118-L140 + libgpgerror-gen-posix-lock-obj = libgpgerror.override { + genPosixLockObjOnly = true; + }; + + libgphoto2 = callPackage ../development/libraries/libgphoto2 { }; + + libgpiod = callPackage ../development/libraries/libgpiod { }; + + libgpod = callPackage ../development/libraries/libgpod { + inherit (pkgs.pythonPackages) mutagen; + }; + + libgssglue = callPackage ../development/libraries/libgssglue { }; + + libgudev = callPackage ../development/libraries/libgudev { }; + + libguestfs-appliance = callPackage ../development/libraries/libguestfs/appliance.nix {}; + libguestfs = callPackage ../development/libraries/libguestfs { }; + libguestfs-with-appliance = libguestfs.override { appliance = libguestfs-appliance; }; + + + libhangul = callPackage ../development/libraries/libhangul { }; + + libharu = callPackage ../development/libraries/libharu { }; + + libhdhomerun = callPackage ../development/libraries/libhdhomerun { }; + + libheif = callPackage ../development/libraries/libheif {}; + + libhttpseverywhere = callPackage ../development/libraries/libhttpseverywhere { }; + + libHX = callPackage ../development/libraries/libHX { }; + + libibmad = callPackage ../development/libraries/libibmad { }; + + libibumad = callPackage ../development/libraries/libibumad { }; + + libical = callPackage ../development/libraries/libical { }; + + libicns = callPackage ../development/libraries/libicns { }; + + libimobiledevice = callPackage ../development/libraries/libimobiledevice { }; + + libindicate-gtk2 = libindicate.override { gtkVersion = "2"; }; + libindicate-gtk3 = libindicate.override { gtkVersion = "3"; }; + libindicate = callPackage ../development/libraries/libindicate { }; + + libindicator-gtk2 = libindicator.override { gtkVersion = "2"; }; + libindicator-gtk3 = libindicator.override { gtkVersion = "3"; }; + libindicator = callPackage ../development/libraries/libindicator { }; + + libinotify-kqueue = callPackage ../development/libraries/libinotify-kqueue { }; + + libiodbc = callPackage ../development/libraries/libiodbc { + inherit (darwin.apple_sdk.frameworks) Carbon; + }; + + libirecovery = callPackage ../development/libraries/libirecovery { }; + + libivykis = callPackage ../development/libraries/libivykis { }; + + liblastfmSF = callPackage ../development/libraries/liblastfmSF { }; + + liblastfm = callPackage ../development/libraries/liblastfm { }; + + liblcf = callPackage ../development/libraries/liblcf { }; + + liblqr1 = callPackage ../development/libraries/liblqr-1 { }; + + liblockfile = callPackage ../development/libraries/liblockfile { }; + + liblogging = callPackage ../development/libraries/liblogging { }; + + liblognorm = callPackage ../development/libraries/liblognorm { }; + + libltc = callPackage ../development/libraries/libltc { }; + + libmaxminddb = callPackage ../development/libraries/libmaxminddb { }; + + libmcrypt = callPackage ../development/libraries/libmcrypt {}; + + libmediaart = callPackage ../development/libraries/libmediaart { }; + + libmediainfo = callPackage ../development/libraries/libmediainfo { }; + + libmhash = callPackage ../development/libraries/libmhash {}; + + libmodbus = callPackage ../development/libraries/libmodbus {}; + + libmtp = callPackage ../development/libraries/libmtp { }; + + libmypaint = callPackage ../development/libraries/libmypaint { }; + + libmysofa = callPackage ../development/libraries/audio/libmysofa { }; + + libmysqlconnectorcpp = callPackage ../development/libraries/libmysqlconnectorcpp { + mysql = mysql57; + }; + + libnatpmp = callPackage ../development/libraries/libnatpmp { }; + + libnatspec = callPackage ../development/libraries/libnatspec { }; + + libndp = callPackage ../development/libraries/libndp { }; + + libnfc = callPackage ../development/libraries/libnfc { }; + + libnfs = callPackage ../development/libraries/libnfs { }; + + libnice = callPackage ../development/libraries/libnice { }; + + libnsl = callPackage ../development/libraries/libnsl { }; + + liboping = callPackage ../development/libraries/liboping { }; + + libplist = callPackage ../development/libraries/libplist { }; + + libre = callPackage ../development/libraries/libre {}; + librem = callPackage ../development/libraries/librem {}; + + librelp = callPackage ../development/libraries/librelp { }; + + librepo = callPackage ../tools/package-management/librepo { }; + + libresample = callPackage ../development/libraries/libresample {}; + + librevenge = callPackage ../development/libraries/librevenge {}; + + librevisa = callPackage ../development/libraries/librevisa { }; + + librime = callPackage ../development/libraries/librime {}; + + libsamplerate = callPackage ../development/libraries/libsamplerate { + inherit (darwin.apple_sdk.frameworks) ApplicationServices Carbon CoreServices; + }; + + libsieve = callPackage ../development/libraries/libsieve { }; + + libsixel = callPackage ../development/libraries/libsixel { }; + + libsolv = callPackage ../development/libraries/libsolv { }; + + libspectre = callPackage ../development/libraries/libspectre { }; + + libgsf = callPackage ../development/libraries/libgsf { }; + + # GNU libc provides libiconv so systems with glibc don't need to build + # libiconv separately. Additionally, Apple forked/repackaged libiconv so we + # use that instead of the vanilla version on that OS. + # + # We also provide `libiconvReal`, which will always be a standalone libiconv, + # just in case you want it regardless of platform. + libiconv = + if lib.elem stdenv.hostPlatform.libc ["glibc" "musl" "wasilibc"] + then glibcIconv (if stdenv.hostPlatform != stdenv.buildPlatform + then libcCross + else stdenv.cc.libc) + else if stdenv.hostPlatform.isDarwin + then darwin.libiconv + else libiconvReal; + + glibcIconv = libc: let + inherit (builtins.parseDrvName libc.name) name version; + libcDev = lib.getDev libc; + in runCommand "${name}-iconv-${version}" {} '' + mkdir -p $out/include + ln -sv ${libcDev}/include/iconv.h $out/include + ''; + + libiconvReal = callPackage ../development/libraries/libiconv { }; + + # On non-GNU systems we need GNU Gettext for libintl. + libintl = if stdenv.hostPlatform.libc != "glibc" then gettext else null; + + libid3tag = callPackage ../development/libraries/libid3tag { + gperf = gperf_3_0; + }; + + libidn = callPackage ../development/libraries/libidn { }; + + libidn2 = callPackage ../development/libraries/libidn2 { }; + + idnkit = callPackage ../development/libraries/idnkit { }; + + libiec61883 = callPackage ../development/libraries/libiec61883 { }; + + libimagequant = callPackage ../development/libraries/libimagequant {}; + + libinfinity = callPackage ../development/libraries/libinfinity { }; + + libinput = callPackage ../development/libraries/libinput { + graphviz = graphviz-nox; + }; + + libinput-gestures = callPackage ../tools/inputmethods/libinput-gestures {}; + + libisofs = callPackage ../development/libraries/libisofs { }; + + libisoburn = callPackage ../development/libraries/libisoburn { }; + + libiptcdata = callPackage ../development/libraries/libiptcdata { }; + + libjpeg_original = callPackage ../development/libraries/libjpeg { }; + libjpeg_turbo = callPackage ../development/libraries/libjpeg-turbo { }; + libjpeg_drop = callPackage ../development/libraries/libjpeg-drop { }; + libjpeg = libjpeg_turbo; + + libjreen = callPackage ../development/libraries/libjreen { }; + + libjson-rpc-cpp = callPackage ../development/libraries/libjson-rpc-cpp { }; + + libkate = callPackage ../development/libraries/libkate { }; + + libksba = callPackage ../development/libraries/libksba { }; + + libksi = callPackage ../development/libraries/libksi { + openssl = openssl_1_0_2; + }; + + liblinear = callPackage ../development/libraries/liblinear { }; + + libmad = callPackage ../development/libraries/libmad { }; + + libmanette = callPackage ../development/libraries/libmanette { }; + + libmatchbox = callPackage ../development/libraries/libmatchbox { }; + + libmatheval = callPackage ../development/libraries/libmatheval { + guile = guile_2_0; + }; + + libmatthew_java = callPackage ../development/libraries/java/libmatthew-java { }; + + libmatroska = callPackage ../development/libraries/libmatroska { }; + + libmd = callPackage ../development/libraries/libmd { }; + + libmemcached = callPackage ../development/libraries/libmemcached { }; + + libmicrohttpd = callPackage ../development/libraries/libmicrohttpd { }; + + libmikmod = callPackage ../development/libraries/libmikmod { + inherit (darwin.apple_sdk.frameworks) CoreAudio; + }; + + libmilter = callPackage ../development/libraries/libmilter { }; + + libminc = callPackage ../development/libraries/libminc { + hdf5 = hdf5_1_8; + }; + + libmirage = callPackage ../misc/emulators/cdemu/libmirage.nix { }; + + libmkv = callPackage ../development/libraries/libmkv { }; + + libmms = callPackage ../development/libraries/libmms { }; + + libmowgli = callPackage ../development/libraries/libmowgli { }; + + libmng = callPackage ../development/libraries/libmng { }; + + libmnl = callPackage ../development/libraries/libmnl { }; + + libmodplug = callPackage ../development/libraries/libmodplug {}; + + libmodule = callPackage ../development/libraries/libmodule { }; + + libmpcdec = callPackage ../development/libraries/libmpcdec { }; + + libmp3splt = callPackage ../development/libraries/libmp3splt { }; + + libmrss = callPackage ../development/libraries/libmrss { }; + + libmspack = callPackage ../development/libraries/libmspack { }; + + libmusicbrainz3 = callPackage ../development/libraries/libmusicbrainz { }; + + libmusicbrainz5 = callPackage ../development/libraries/libmusicbrainz/5.x.nix { }; + + libmusicbrainz = libmusicbrainz3; + + libmwaw = callPackage ../development/libraries/libmwaw { }; + + libmx = callPackage ../development/libraries/libmx { }; + + libndctl = callPackage ../development/libraries/libndctl { }; + + libnet = callPackage ../development/libraries/libnet { }; + + libnetfilter_acct = callPackage ../development/libraries/libnetfilter_acct { }; + + libnetfilter_conntrack = callPackage ../development/libraries/libnetfilter_conntrack { }; + + libnetfilter_cthelper = callPackage ../development/libraries/libnetfilter_cthelper { }; + + libnetfilter_cttimeout = callPackage ../development/libraries/libnetfilter_cttimeout { }; + + libnetfilter_log = callPackage ../development/libraries/libnetfilter_log { }; + + libnetfilter_queue = callPackage ../development/libraries/libnetfilter_queue { }; + + libnfnetlink = callPackage ../development/libraries/libnfnetlink { }; + + libnftnl = callPackage ../development/libraries/libnftnl { }; + + libnih = callPackage ../development/libraries/libnih { }; + + libnova = callPackage ../development/libraries/libnova { }; + + libnxml = callPackage ../development/libraries/libnxml { }; + + libodfgen = callPackage ../development/libraries/libodfgen { }; + + libofa = callPackage ../development/libraries/libofa { }; + + libofx = callPackage ../development/libraries/libofx { }; + + libogg = callPackage ../development/libraries/libogg { }; + + liboggz = callPackage ../development/libraries/liboggz { }; + + liboil = callPackage ../development/libraries/liboil { }; + + libomxil-bellagio = callPackage ../development/libraries/libomxil-bellagio { }; + + liboop = callPackage ../development/libraries/liboop { }; + + libopenaptx = callPackage ../development/libraries/libopenaptx { }; + + libopus = callPackage ../development/libraries/libopus { }; + + libopusenc = callPackage ../development/libraries/libopusenc { }; + + libosinfo = callPackage ../development/libraries/libosinfo { + inherit (gnome3) libsoup; + }; + + libosip = callPackage ../development/libraries/osip {}; + + libosmium = callPackage ../development/libraries/libosmium { }; + + libosmocore = callPackage ../applications/misc/libosmocore { }; + + libosmpbf = callPackage ../development/libraries/libosmpbf {}; + + libotr = callPackage ../development/libraries/libotr { }; + + libow = callPackage ../development/libraries/libow { }; + + libp11 = callPackage ../development/libraries/libp11 { }; + + libpar2 = callPackage ../development/libraries/libpar2 { }; + + libpcap = callPackage ../development/libraries/libpcap { }; + + libpeas = callPackage ../development/libraries/libpeas { }; + + libpipeline = callPackage ../development/libraries/libpipeline { }; + + libpgf = callPackage ../development/libraries/libpgf { }; + + libphonenumber = callPackage ../development/libraries/libphonenumber { }; + + libpng = callPackage ../development/libraries/libpng { }; + libpng_apng = libpng.override { apngSupport = true; }; + libpng12 = callPackage ../development/libraries/libpng/12.nix { }; + + libpaper = callPackage ../development/libraries/libpaper { }; + + libpfm = callPackage ../development/libraries/libpfm { }; + + libpqxx = callPackage ../development/libraries/libpqxx { }; + + libproxy = callPackage ../development/libraries/libproxy { + inherit (darwin.apple_sdk.frameworks) SystemConfiguration CoreFoundation JavaScriptCore; + }; + + libpseudo = callPackage ../development/libraries/libpseudo { }; + + libpsl = callPackage ../development/libraries/libpsl { }; + + libpst = callPackage ../development/libraries/libpst { }; + + libpwquality = callPackage ../development/libraries/libpwquality { }; + + libqalculate = callPackage ../development/libraries/libqalculate { }; + + libroxml = callPackage ../development/libraries/libroxml { }; + + librsvg = callPackage ../development/libraries/librsvg { }; + + librsync = callPackage ../development/libraries/librsync { }; + + librsync_0_9 = callPackage ../development/libraries/librsync/0.9.nix { }; + + libs3 = callPackage ../development/libraries/libs3 { }; + + libsearpc = callPackage ../development/libraries/libsearpc { }; + + libsigcxx = callPackage ../development/libraries/libsigcxx { }; + + libsigcxx12 = callPackage ../development/libraries/libsigcxx/1.2.nix { }; + + libsigsegv = callPackage ../development/libraries/libsigsegv { }; + + libsndfile = callPackage ../development/libraries/libsndfile { + inherit (darwin.apple_sdk.frameworks) Carbon AudioToolbox; + }; + + libsnark = callPackage ../development/libraries/libsnark { }; + + libsodium = callPackage ../development/libraries/libsodium { }; + + libsoup = callPackage ../development/libraries/libsoup { }; + + libspiro = callPackage ../development/libraries/libspiro {}; + + libssh = callPackage ../development/libraries/libssh { }; + + libssh2 = callPackage ../development/libraries/libssh2 { }; + + libstartup_notification = callPackage ../development/libraries/startup-notification { }; + + libstemmer = callPackage ../development/libraries/libstemmer { }; + + libstroke = callPackage ../development/libraries/libstroke { }; + + libstrophe = callPackage ../development/libraries/libstrophe { }; + + libspatialindex = callPackage ../development/libraries/libspatialindex { }; + + libspatialite = callPackage ../development/libraries/libspatialite { }; + + libstatgrab = callPackage ../development/libraries/libstatgrab { + inherit (darwin.apple_sdk.frameworks) IOKit; + }; + + libsvm = callPackage ../development/libraries/libsvm { }; + + libtar = callPackage ../development/libraries/libtar { }; + + libtasn1 = callPackage ../development/libraries/libtasn1 { }; + + libtcod = callPackage ../development/libraries/libtcod { }; + + libtheora = callPackage ../development/libraries/libtheora { }; + + libtiff = callPackage ../development/libraries/libtiff { }; + + libtiger = callPackage ../development/libraries/libtiger { }; + + libtommath = callPackage ../development/libraries/libtommath { }; + + libtomcrypt = callPackage ../development/libraries/libtomcrypt { }; + + libtorrentRasterbar = callPackage ../development/libraries/libtorrent-rasterbar { }; + + # this is still the new version of the old API + libtoxcore-new = callPackage ../development/libraries/libtoxcore/new-api.nix { }; + + inherit (callPackages ../development/libraries/libtoxcore {}) + libtoxcore_0_1 libtoxcore_0_2; + libtoxcore = libtoxcore_0_2; + + libtap = callPackage ../development/libraries/libtap { }; + + libtsm = callPackage ../development/libraries/libtsm { }; + + libtxc_dxtn = callPackage ../development/libraries/libtxc_dxtn { }; + + libtxc_dxtn_s2tc = callPackage ../development/libraries/libtxc_dxtn_s2tc { }; + + libgeotiff = callPackage ../development/libraries/libgeotiff { }; + + libu2f-host = callPackage ../development/libraries/libu2f-host { }; + + libu2f-server = callPackage ../development/libraries/libu2f-server { }; + + libubox = callPackage ../development/libraries/libubox { }; + + libuecc = callPackage ../development/libraries/libuecc { }; + + libui = callPackage ../development/libraries/libui { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + + libunistring = callPackage ../development/libraries/libunistring { }; + + libupnp = callPackage ../development/libraries/pupnp { }; + + libwhereami = callPackage ../development/libraries/libwhereami { }; + + giflib = giflib_5_1; + giflib_4_1 = callPackage ../development/libraries/giflib/4.1.nix { }; + giflib_5_1 = callPackage ../development/libraries/giflib/5.1.nix { }; + + libunarr = callPackage ../development/libraries/libunarr { }; + + libungif = callPackage ../development/libraries/giflib/libungif.nix { }; + + libunibreak = callPackage ../development/libraries/libunibreak { }; + + libunique = callPackage ../development/libraries/libunique { }; + libunique3 = callPackage ../development/libraries/libunique/3.x.nix { }; + + liburcu = callPackage ../development/libraries/liburcu { }; + + libusb = callPackage ../development/libraries/libusb {}; + + libusb1 = callPackage ../development/libraries/libusb1 { + inherit (darwin) libobjc; + inherit (darwin.apple_sdk.frameworks) IOKit; + }; + + libusbmuxd = callPackage ../development/libraries/libusbmuxd { }; + + libutempter = callPackage ../development/libraries/libutempter { }; + + libunwind = if stdenv.isDarwin + then darwin.libunwind + else callPackage ../development/libraries/libunwind { }; + + libuv = callPackage ../development/libraries/libuv { + inherit (darwin.apple_sdk.frameworks) ApplicationServices CoreServices; + }; + + libv4l = lowPrio (v4l-utils.override { + withUtils = false; + }); + + libva = callPackage ../development/libraries/libva { }; + libva-minimal = libva.override { minimal = true; }; + libva-utils = callPackage ../development/libraries/libva-utils { }; + + libva1 = callPackage ../development/libraries/libva/1.0.0.nix { }; + libva1-minimal = libva1.override { minimal = true; }; + + libvdpau = callPackage ../development/libraries/libvdpau { }; + + libmodulemd = callPackage ../development/libraries/libmodulemd { }; + libmodulemd_1 = callPackage ../development/libraries/libmodulemd/1.nix { }; + + libvdpau-va-gl = callPackage ../development/libraries/libvdpau-va-gl { }; + + libversion = callPackage ../development/libraries/libversion { }; + + libvirt = callPackage ../development/libraries/libvirt { }; + + libvirt-glib = callPackage ../development/libraries/libvirt-glib { }; + + libvisio = callPackage ../development/libraries/libvisio { }; + + libvisual = callPackage ../development/libraries/libvisual { }; + + libvncserver = callPackage ../development/libraries/libvncserver {}; + + libviper = callPackage ../development/libraries/libviper { }; + + libvpx = callPackage ../development/libraries/libvpx { }; + + libvterm = callPackage ../development/libraries/libvterm { }; + libvterm-neovim = callPackage ../development/libraries/libvterm-neovim { }; + + libvorbis = callPackage ../development/libraries/libvorbis { }; + + libwebcam = callPackage ../os-specific/linux/libwebcam { }; + + libwebp = callPackage ../development/libraries/libwebp { }; + + libwmf = callPackage ../development/libraries/libwmf { }; + + libwnck = libwnck2; + libwnck2 = callPackage ../development/libraries/libwnck { }; + libwnck3 = callPackage ../development/libraries/libwnck/3.x.nix { }; + + libwpd = callPackage ../development/libraries/libwpd { }; + + libwpd_08 = callPackage ../development/libraries/libwpd/0.8.nix { }; + + libwps = callPackage ../development/libraries/libwps { }; + + libwpg = callPackage ../development/libraries/libwpg { }; + + libx86 = callPackage ../development/libraries/libx86 {}; + + libxdg_basedir = callPackage ../development/libraries/libxdg-basedir { }; + + libxkbcommon = libxkbcommon_8; + libxkbcommon_8 = callPackage ../development/libraries/libxkbcommon { }; + libxkbcommon_7 = callPackage ../development/libraries/libxkbcommon/libxkbcommon_7.nix { }; + + libxklavier = callPackage ../development/libraries/libxklavier { }; + + libxls = callPackage ../development/libraries/libxls { }; + + libxmi = callPackage ../development/libraries/libxmi { }; + + libxml2 = callPackage ../development/libraries/libxml2 { }; + + libxml2Python = pkgs.buildEnv { # slightly hacky + name = "libxml2+py-${res.libxml2.version}"; + paths = with libxml2; [ dev bin py ]; + inherit (libxml2) passthru; + # the hook to find catalogs is hidden by buildEnv + postBuild = '' + mkdir "$out/nix-support" + cp '${libxml2.dev}/nix-support/propagated-build-inputs' "$out/nix-support/" + ''; + }; + + libxmlb = callPackage ../development/libraries/libxmlb { }; + + libxmlxx = callPackage ../development/libraries/libxmlxx { }; + libxmlxx3 = callPackage ../development/libraries/libxmlxx/v3.nix { }; + + libxmp = callPackage ../development/libraries/libxmp { }; + + libxslt = callPackage ../development/libraries/libxslt { }; + + libixp_hg = callPackage ../development/libraries/libixp-hg { }; + + libyaml = callPackage ../development/libraries/libyaml { }; + + libyamlcpp = callPackage ../development/libraries/libyaml-cpp { }; + + libyamlcpp_0_3 = pkgs.libyamlcpp.overrideAttrs (oldAttrs: rec { + src = pkgs.fetchurl { + url = "https://github.com/jbeder/yaml-cpp/archive/release-0.3.0.tar.gz"; + sha256 = "12aszqw6svwlnb6nzhsbqhz3c7vnd5ahd0k6xlj05w8lm83hx3db"; + }; + }); + + libykclient = callPackage ../development/libraries/libykclient { }; + + libykneomgr = callPackage ../development/libraries/libykneomgr { }; + + libytnef = callPackage ../development/libraries/libytnef { }; + + libyubikey = callPackage ../development/libraries/libyubikey { }; + + libzapojit = callPackage ../development/libraries/libzapojit { }; + + libzen = callPackage ../development/libraries/libzen { }; + + libzip = callPackage ../development/libraries/libzip { }; + + libzdb = callPackage ../development/libraries/libzdb { }; + + libwacom = callPackage ../development/libraries/libwacom { }; + + lightning = callPackage ../development/libraries/lightning { }; + + lightlocker = callPackage ../misc/screensavers/light-locker { }; + + lightstep-tracer-cpp = callPackage ../development/libraries/lightstep-tracer-cpp { }; + + linenoise = callPackage ../development/libraries/linenoise { }; + + linenoise-ng = callPackage ../development/libraries/linenoise-ng { }; + + lirc = callPackage ../development/libraries/lirc { }; + + liquid-dsp = callPackage ../development/libraries/liquid-dsp { }; + + liquidfun = callPackage ../development/libraries/liquidfun { }; + + live555 = callPackage ../development/libraries/live555 { }; + + loadcaffe = callPackage ../development/libraries/loadcaffe {}; + + log4cpp = callPackage ../development/libraries/log4cpp { }; + + log4cxx = callPackage ../development/libraries/log4cxx { }; + + log4cplus = callPackage ../development/libraries/log4cplus { }; + + log4shib = callPackage ../development/libraries/log4shib { }; + + loudmouth = callPackage ../development/libraries/loudmouth { }; + + luabind = callPackage ../development/libraries/luabind { lua = lua5_1; }; + + luabind_luajit = luabind.override { lua = luajit; }; + + lzo = callPackage ../development/libraries/lzo { }; + + mapnik = callPackage ../development/libraries/mapnik { }; + + marisa = callPackage ../development/libraries/marisa {}; + + matio = callPackage ../development/libraries/matio { }; + + mbedtls = callPackage ../development/libraries/mbedtls { }; + mbedtls_1_3 = callPackage ../development/libraries/mbedtls/1.3.nix { }; + polarssl = mbedtls; # TODO: add to aliases.nix + + mdds = callPackage ../development/libraries/mdds { }; + + mediastreamer = callPackage ../development/libraries/mediastreamer { }; + + mediastreamer-openh264 = callPackage ../development/libraries/mediastreamer/msopenh264.nix { }; + + menu-cache = callPackage ../development/libraries/menu-cache { }; + + mergerfs = callPackage ../tools/filesystems/mergerfs { }; + + mergerfs-tools = callPackage ../tools/filesystems/mergerfs/tools.nix { }; + + ## libGL/libGLU/Mesa stuff + + # Default libGL implementation, should provide headers and + # libGL.so/libEGL.so/... to link agains them. Android NDK provides + # an OpenGL implementation, we can just use that. + libGL = if stdenv.hostPlatform.useAndroidPrebuilt then stdenv + else callPackage ../development/libraries/mesa/stubs.nix { + inherit (darwin.apple_sdk.frameworks) OpenGL; + }; + + # Default libGLU + libGLU = mesa_glu; + + # Combined derivation, contains both libGL and libGLU + # Please, avoid using this attribute. It was meant as transitional hack + # for packages that assume that libGLU and libGL live in the same prefix. + # libGLU_combined propagates both libGL and libGLU + libGLU_combined = buildEnv { + name = "libGLU-combined"; + paths = [ libGL libGLU ]; + extraOutputsToInstall = [ "dev" ]; + }; + + mesa = callPackage ../development/libraries/mesa { + # 7 is the default, but only on Linux, so keep this for now + llvmPackages = llvmPackages_7; + inherit (darwin.apple_sdk.frameworks) OpenGL; + inherit (darwin.apple_sdk.libs) Xplugin; + }; + + mesa_glu = callPackage ../development/libraries/mesa-glu { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + }; + + ## End libGL/libGLU/Mesa stuff + + meterbridge = callPackage ../applications/audio/meterbridge { }; + + mhddfs = callPackage ../tools/filesystems/mhddfs { }; + + microsoft_gsl = callPackage ../development/libraries/microsoft_gsl { }; + + minizip = callPackage ../development/libraries/minizip { }; + + mkvtoolnix = libsForQt5.callPackage ../applications/video/mkvtoolnix { }; + + mkvtoolnix-cli = callPackage ../applications/video/mkvtoolnix { + withGUI = false; + }; + + mlt = callPackage ../development/libraries/mlt {}; + + mono-addins = callPackage ../development/libraries/mono-addins { }; + + mono-zeroconf = callPackage ../development/libraries/mono-zeroconf { }; + + movit = callPackage ../development/libraries/movit { }; + + mosquitto = callPackage ../servers/mqtt/mosquitto { }; + + mps = callPackage ../development/libraries/mps { }; + + libmpeg2 = callPackage ../development/libraries/libmpeg2 { }; + + mpeg2dec = libmpeg2; + + mqtt-bench = callPackage ../applications/misc/mqtt-bench {}; + + msgpack = callPackage ../development/libraries/msgpack { }; + + msilbc = callPackage ../development/libraries/msilbc { }; + + mp4v2 = callPackage ../development/libraries/mp4v2 { }; + + libmpc = callPackage ../development/libraries/libmpc { }; + + mpich = callPackage ../development/libraries/mpich { }; + + mstpd = callPackage ../os-specific/linux/mstpd { }; + + mtdev = callPackage ../development/libraries/mtdev { }; + + mtpfs = callPackage ../tools/filesystems/mtpfs { }; + + mtxclient = callPackage ../development/libraries/mtxclient { }; + + mu = callPackage ../tools/networking/mu { + texinfo = texinfo4; + }; + + mueval = callPackage ../development/tools/haskell/mueval { }; + + mumlib = callPackage ../development/libraries/mumlib { }; + + muparser = callPackage ../development/libraries/muparser { }; + + mutest = callPackage ../development/libraries/mutest { }; + + mygpoclient = pythonPackages.mygpoclient; + + mygui = callPackage ../development/libraries/mygui { + ogre = ogre1_9; + }; + + mysocketw = callPackage ../development/libraries/mysocketw { + openssl = openssl_1_0_2; + }; + + mythes = callPackage ../development/libraries/mythes { }; + + nanoflann = callPackage ../development/libraries/nanoflann { }; + + nanomsg = callPackage ../development/libraries/nanomsg { }; + + ndpi = callPackage ../development/libraries/ndpi { }; + + nifticlib = callPackage ../development/libraries/science/biology/nifticlib { }; + + notify-sharp = callPackage ../development/libraries/notify-sharp { }; + + ncurses5 = ncurses.override { + abiVersion = "5"; + }; + ncurses6 = ncurses.override { + abiVersion = "6"; + }; + ncurses = + if stdenv.hostPlatform.useiOSPrebuilt + then null + else callPackage ../development/libraries/ncurses { }; + + neardal = callPackage ../development/libraries/neardal { }; + + neon = callPackage ../development/libraries/neon { }; + + neon_0_29 = callPackage ../development/libraries/neon/0.29.nix { + openssl = openssl_1_0_2; + }; + + nettle = callPackage ../development/libraries/nettle { }; + + newt = callPackage ../development/libraries/newt { }; + + nghttp2 = callPackage ../development/libraries/nghttp2 { }; + libnghttp2 = nghttp2.lib; + + nix-plugins = callPackage ../development/libraries/nix-plugins { + nix = nixUnstable; + }; + + nika-fonts = callPackage ../data/fonts/nika-fonts { }; + + nlohmann_json = callPackage ../development/libraries/nlohmann_json { }; + + nntp-proxy = callPackage ../applications/networking/nntp-proxy { }; + + non = callPackage ../applications/audio/non { }; + + ntl = callPackage ../development/libraries/ntl { }; + + nspr = callPackage ../development/libraries/nspr { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + nss = lowPrio (callPackage ../development/libraries/nss { }); + nssTools = nss.tools; + + nss_wrapper = callPackage ../development/libraries/nss_wrapper { }; + + nsss = skawarePackages.nsss; + + ntbtls = callPackage ../development/libraries/ntbtls { }; + + ntk = callPackage ../development/libraries/audio/ntk { }; + + ntrack = callPackage ../development/libraries/ntrack { }; + + nuspell = callPackage ../development/libraries/nuspell { }; + nuspellWithDicts = dicts: callPackage ../development/libraries/nuspell/wrapper.nix { inherit dicts; }; + + nv-codec-headers = callPackage ../development/libraries/nv-codec-headers { }; + + nvidia-docker = callPackage ../applications/virtualization/nvidia-docker { }; + + nvidia-texture-tools = callPackage ../development/libraries/nvidia-texture-tools { }; + + nvidia-video-sdk = callPackage ../development/libraries/nvidia-video-sdk { }; + + nvtop = callPackage ../tools/system/nvtop { + nvidia_x11 = linuxPackages.nvidia_x11.override { libsOnly = true; }; + }; + + ocl-icd-oclhGen = oclh: callPackage ../development/libraries/ocl-icd { opencl-headers = oclh; }; + ocl-icd-oclh_1_2 = ocl-icd-oclhGen opencl-headers_1_2; + ocl-icd-oclh_2_2 = ocl-icd-oclhGen opencl-headers_2_2; + ocl-icd = ocl-icd-oclh_2_2; + + ode = callPackage ../development/libraries/ode { }; + + ogre = callPackage ../development/libraries/ogre {}; + ogre1_9 = callPackage ../development/libraries/ogre/1.9.x.nix {}; + ogre1_10 = callPackage ../development/libraries/ogre/1.10.x.nix {}; + + ogrepaged = callPackage ../development/libraries/ogrepaged { }; + + olm = callPackage ../development/libraries/olm { }; + + one_gadget = callPackage ../development/tools/misc/one_gadget { }; + + oneko = callPackage ../applications/misc/oneko { }; + + oniguruma = callPackage ../development/libraries/oniguruma { }; + + oobicpl = callPackage ../development/libraries/science/biology/oobicpl { }; + + openalSoft = callPackage ../development/libraries/openal-soft { + inherit (darwin.apple_sdk.frameworks) CoreServices AudioUnit AudioToolbox; + }; + openal = openalSoft; + + openbabel = callPackage ../development/libraries/openbabel { }; + + opencascade = callPackage ../development/libraries/opencascade { }; + opencascade-occt = callPackage ../development/libraries/opencascade-occt { }; + + opencl-headersGen = v: callPackage ../development/libraries/opencl-headers { version = v; }; + opencl-headers_1_2 = opencl-headersGen "12"; + opencl-headers_2_2 = opencl-headersGen "22"; + opencl-headers = opencl-headers_2_2; + + opencl-clhpp = callPackage ../development/libraries/opencl-clhpp { }; + + opencollada = callPackage ../development/libraries/opencollada { }; + + opencore-amr = callPackage ../development/libraries/opencore-amr { }; + + opencsg = callPackage ../development/libraries/opencsg { + inherit (qt5) qmake; + inherit (darwin.apple_sdk.frameworks) GLUT; + }; + + openct = callPackage ../development/libraries/openct { }; + + opencv = callPackage ../development/libraries/opencv { + inherit (darwin.apple_sdk.frameworks) Cocoa QTKit; + }; + + opencv3 = callPackage ../development/libraries/opencv/3.x.nix { + inherit (darwin.apple_sdk.frameworks) AVFoundation Cocoa VideoDecodeAcceleration; + }; + + opencv3WithoutCuda = opencv3.override { + enableCuda = false; + }; + + opencv4 = callPackage ../development/libraries/opencv/4.x.nix { + inherit (darwin.apple_sdk.frameworks) AVFoundation Cocoa VideoDecodeAcceleration; + }; + + openexr = callPackage ../development/libraries/openexr { }; + + openexrid-unstable = callPackage ../development/libraries/openexrid-unstable { }; + + openldap = callPackage ../development/libraries/openldap { }; + + opencolorio = callPackage ../development/libraries/opencolorio { }; + + ois = callPackage ../development/libraries/ois {}; + + opal = callPackage ../development/libraries/opal { + ffmpeg = ffmpeg_2; + stdenv = gcc6Stdenv; + }; + + openh264 = callPackage ../development/libraries/openh264 { }; + + openjpeg_1 = callPackage ../development/libraries/openjpeg/1.x.nix { }; + openjpeg_2 = callPackage ../development/libraries/openjpeg/2.x.nix { }; + openjpeg = openjpeg_2; + + openpa = callPackage ../development/libraries/openpa { }; + + opensaml-cpp = callPackage ../development/libraries/opensaml-cpp { }; + + openscenegraph = callPackage ../development/libraries/openscenegraph { }; + + openslp = callPackage ../development/libraries/openslp {}; + + openvdb = callPackage ../development/libraries/openvdb {}; + + inherit (callPackages ../development/libraries/libressl { }) + libressl_2_8 + libressl_2_9 + libressl_3_0; + + libressl = libressl_2_9; + + boringssl = callPackage ../development/libraries/boringssl { }; + + wolfssl = callPackage ../development/libraries/wolfssl { }; + + openssl = openssl_1_1; + + inherit (callPackages ../development/libraries/openssl { }) + openssl_1_0_2 + openssl_1_1; + + openssl-chacha = callPackage ../development/libraries/openssl/chacha.nix { }; + + opensubdiv = callPackage ../development/libraries/opensubdiv { + cmake = cmake_2_8; + }; + + open-wbo = callPackage ../applications/science/logic/open-wbo {}; + + openwsman = callPackage ../development/libraries/openwsman {}; + + ortp = callPackage ../development/libraries/ortp { }; + + openhmd = callPackage ../development/libraries/openhmd { }; + + openrct2 = callPackage ../games/openrct2 { }; + + orcania = callPackage ../development/libraries/orcania { }; + + osm-gps-map = callPackage ../development/libraries/osm-gps-map { }; + + osinfo-db = callPackage ../data/misc/osinfo-db { }; + osinfo-db-tools = callPackage ../tools/misc/osinfo-db-tools { }; + + p11-kit = callPackage ../development/libraries/p11-kit { }; + + paperkey = callPackage ../tools/security/paperkey { }; + + pangoxsl = callPackage ../development/libraries/pangoxsl { }; + + pcaudiolib = callPackage ../development/libraries/pcaudiolib { }; + + pcg_c = callPackage ../development/libraries/pcg-c { }; + + pcl = libsForQt5.callPackage ../development/libraries/pcl { + inherit (darwin.apple_sdk.frameworks) Cocoa AGL OpenGL; + }; + + pcre = callPackage ../development/libraries/pcre { }; + pcre16 = res.pcre.override { variant = "pcre16"; }; + # pcre32 seems unused + pcre-cpp = res.pcre.override { variant = "cpp"; }; + + pcre2 = callPackage ../development/libraries/pcre2 { }; + + pdf2xml = callPackage ../development/libraries/pdf2xml {} ; + + phonon = callPackage ../development/libraries/phonon {}; + + phonon-backend-gstreamer = callPackage ../development/libraries/phonon/backends/gstreamer.nix {}; + + # TODO(@Ma27) get rid of that as soon as QT4 can be dropped + phonon-backend-vlc = callPackage ../development/libraries/phonon/backends/vlc.nix { + withQt4 = true; + }; + + inherit (callPackage ../development/libraries/physfs { }) + physfs_2 + physfs; + + pipelight = callPackage ../tools/misc/pipelight { + stdenv = stdenv_32bit; + wine-staging = pkgsi686Linux.wine-staging; + }; + + pkcs11helper = callPackage ../development/libraries/pkcs11helper { }; + + plib = callPackage ../development/libraries/plib { }; + + pocketsphinx = callPackage ../development/libraries/pocketsphinx { }; + + poco = callPackage ../development/libraries/poco { }; + + podofo = callPackage ../development/libraries/podofo { lua5 = lua5_1; }; + + polkit = callPackage ../development/libraries/polkit { }; + + polkit_qt4 = callPackage ../development/libraries/polkit-qt-1/qt-4.nix { }; + + poppler = callPackage ../development/libraries/poppler { lcms = lcms2; }; + poppler_0_61 = callPackage ../development/libraries/poppler/0.61.nix { lcms = lcms2; }; + + poppler_gi = lowPrio (poppler.override { + introspectionSupport = true; + }); + + poppler_min = poppler.override { # TODO: maybe reduce even more + # this is currently only used by texlive.bin. + minimal = true; + suffix = "min"; + }; + + poppler_utils = poppler.override { suffix = "utils"; utils = true; }; + + popt = callPackage ../development/libraries/popt { }; + + portaudio = callPackage ../development/libraries/portaudio { + inherit (darwin.apple_sdk.frameworks) AudioToolbox AudioUnit CoreAudio CoreServices Carbon; + }; + + portaudio2014 = portaudio.overrideAttrs (oldAttrs: { + src = fetchurl { + url = http://www.portaudio.com/archives/pa_stable_v19_20140130.tgz; + sha256 = "0mwddk4qzybaf85wqfhxqlf0c5im9il8z03rd4n127k8y2jj9q4g"; + }; + }); + + portmidi = callPackage ../development/libraries/portmidi {}; + + primesieve = callPackage ../development/libraries/science/math/primesieve { }; + + prison = callPackage ../development/libraries/prison { }; + + proj = callPackage ../development/libraries/proj { }; + + proj_5 = callPackage ../development/libraries/proj/5.2.nix { }; + + proj-datumgrid = callPackage ../development/libraries/proj-datumgrid { }; + + proselint = callPackage ../tools/text/proselint { + inherit (python3Packages) + buildPythonApplication click future six; + }; + + protobuf = protobuf3_7; + + protobuf3_9 = callPackage ../development/libraries/protobuf/3.9.nix { }; + protobuf3_8 = callPackage ../development/libraries/protobuf/3.8.nix { }; + protobuf3_7 = callPackage ../development/libraries/protobuf/3.7.nix { }; + protobuf3_6 = callPackage ../development/libraries/protobuf/3.6.nix { }; + protobuf3_1 = callPackage ../development/libraries/protobuf/3.1.nix { }; + protobuf2_5 = callPackage ../development/libraries/protobuf/2.5.nix { }; + + protobufc = callPackage ../development/libraries/protobufc/1.3.nix { }; + + protozero = callPackage ../development/libraries/protozero { }; + + flatbuffers = callPackage ../development/libraries/flatbuffers { }; + + gnupth = callPackage ../development/libraries/pth { }; + pth = if stdenv.hostPlatform.isMusl then npth else gnupth; + + ptlib = callPackage ../development/libraries/ptlib {}; + + pugixml = callPackage ../development/libraries/pugixml { }; + + pybind11 = callPackage ../development/libraries/pybind11 { }; + + python-qt = callPackage ../development/libraries/python-qt { + python = python27; + qmake = qt59.qmake; + qttools = qt59.qttools; + qtwebengine = qt59.qtwebengine; + qtxmlpatterns = qt59.qtxmlpatterns; + }; + + pyotherside = libsForQt5.callPackage ../development/libraries/pyotherside {}; + + re2 = callPackage ../development/libraries/re2 { }; + + qbs = libsForQt5.callPackage ../development/tools/build-managers/qbs { }; + + qca2 = callPackage ../development/libraries/qca2 { qt = qt4; }; + qca2-qt5 = qca2.override { qt = qt5.qtbase; }; + + qimageblitz = callPackage ../development/libraries/qimageblitz {}; + + qjson = callPackage ../development/libraries/qjson { }; + + qoauth = callPackage ../development/libraries/qoauth { }; + + qolibri = libsForQt5.callPackage ../applications/misc/qolibri { }; + + qt3 = callPackage ../development/libraries/qt-3 { + libpng = libpng12; + }; + + qt4 = qt48; + + qt48 = callPackage ../development/libraries/qt-4.x/4.8 { + # GNOME dependencies are not used unless gtkStyle == true + inherit (pkgs.gnome2) libgnomeui GConf gnome_vfs; + cups = if stdenv.isLinux then cups else null; + + # XXX: mariadb doesn't built on fbsd as of nov 2015 + mysql = if (!stdenv.isFreeBSD) then mysql else null; + + inherit (pkgs.darwin) libobjc; + inherit (pkgs.darwin.apple_sdk.frameworks) ApplicationServices OpenGL Cocoa AGL; + }; + + qmake48Hook = makeSetupHook + { substitutions = { qt4 = qt48; }; } + ../development/libraries/qt-4.x/4.8/qmake-hook.sh; + + qmake4Hook = qmake48Hook; + + qt48Full = appendToName "full" (qt48.override { + docs = true; + demos = true; + examples = true; + developerBuild = true; + }); + + qt59 = recurseIntoAttrs (makeOverridable + (import ../development/libraries/qt-5/5.9) { + inherit newScope; + inherit stdenv fetchurl fetchpatch makeSetupHook makeWrapper; + bison = bison2; # error: too few arguments to function 'int yylex(... + inherit cups; + harfbuzz = harfbuzzFull; + inherit libGL; + inherit perl; + inherit (gst_all_1) gstreamer gst-plugins-base; + inherit gtk3; + inherit (gnome3) dconf; + }); + + libsForQt59 = lib.makeScope qt59.newScope mkLibsForQt5; + + qt511 = recurseIntoAttrs (makeOverridable + (import ../development/libraries/qt-5/5.11) { + inherit newScope; + inherit stdenv fetchurl fetchFromGitHub makeSetupHook makeWrapper; + bison = bison2; # error: too few arguments to function 'int yylex(... + inherit cups; + harfbuzz = harfbuzzFull; + inherit libGL; + inherit perl; + inherit gtk3; + inherit (gnome3) dconf; + inherit (gst_all_1) gstreamer gst-plugins-base; + inherit llvmPackages_5; + }); + + libsForQt511 = recurseIntoAttrs (lib.makeScope qt511.newScope mkLibsForQt5); + + qt512 = recurseIntoAttrs (makeOverridable + (import ../development/libraries/qt-5/5.12) { + inherit newScope; + inherit stdenv fetchurl fetchFromGitHub makeSetupHook makeWrapper; + bison = bison2; # error: too few arguments to function 'int yylex(... + inherit cups; + harfbuzz = harfbuzzFull; + inherit libGL; + inherit perl; + inherit gtk3; + inherit (gnome3) dconf; + inherit (gst_all_1) gstreamer gst-plugins-base; + inherit llvmPackages_5; + }); + + libsForQt512 = recurseIntoAttrs (lib.makeScope qt512.newScope mkLibsForQt5); + + qt5 = qt512; + libsForQt5 = if stdenv.isDarwin then libsForQt511 else libsForQt512; + + qt5ct = libsForQt5.callPackage ../tools/misc/qt5ct { }; + + mkLibsForQt5 = self: with self; { + + ### KDE FRAMEWORKS + + inherit (kdeFrameworks.override { libsForQt5 = self; }) + attica baloo bluez-qt kactivities kactivities-stats + karchive kauth kbookmarks kcmutils kcodecs kcompletion kconfig + kconfigwidgets kcoreaddons kcrash kdbusaddons kdeclarative kdelibs4support + kdesignerplugin kdnssd kemoticons kfilemetadata kglobalaccel kguiaddons + khtml ki18n kiconthemes kidletime kimageformats kio kitemmodels kitemviews + kjobwidgets kjs kjsembed kmediaplayer knewstuff knotifications + knotifyconfig kpackage kparts kpeople kplotting kpty kross krunner + kservice ktexteditor ktextwidgets kunitconversion kwallet kwayland + kwidgetsaddons kwindowsystem kxmlgui kxmlrpcclient modemmanager-qt + networkmanager-qt plasma-framework prison solid sonnet syntax-highlighting + syndication threadweaver kirigami2 kholidays kpurpose; + + ### KDE PLASMA 5 + + inherit (plasma5.override { libsForQt5 = self; }) + kdecoration khotkeys libkscreen libksysguard; + + ### KDE APPLICATIONS + + inherit (kdeApplications.override { libsForQt5 = self; }) + libkdcraw libkexiv2 libkipi libkomparediff2 libksane; + + ### LIBRARIES + + accounts-qt = callPackage ../development/libraries/accounts-qt { }; + + alkimia = callPackage ../development/libraries/alkimia { }; + + fcitx-qt5 = callPackage ../tools/inputmethods/fcitx/fcitx-qt5.nix { }; + + qgpgme = callPackage ../development/libraries/gpgme { }; + + grantlee = callPackage ../development/libraries/grantlee/5 { }; + + kdb = callPackage ../development/libraries/kdb { }; + + kdiagram = callPackage ../development/libraries/kdiagram { }; + + kproperty = callPackage ../development/libraries/kproperty { }; + + kreport = callPackage ../development/libraries/kreport { }; + + libcommuni = callPackage ../development/libraries/libcommuni { }; + + libdbusmenu = callPackage ../development/libraries/libdbusmenu-qt/qt-5.5.nix { }; + + libkeyfinder = callPackage ../development/libraries/libkeyfinder { }; + + libktorrent = callPackage ../development/libraries/libktorrent { }; + + libopenshot = callPackage ../applications/video/openshot-qt/libopenshot.nix { }; + + libopenshot-audio = callPackage ../applications/video/openshot-qt/libopenshot-audio.nix { }; + + libqglviewer = callPackage ../development/libraries/libqglviewer { + inherit (darwin.apple_sdk.frameworks) AGL; + }; + + libqtav = callPackage ../development/libraries/libqtav { }; + + kpmcore = callPackage ../development/libraries/kpmcore { }; + + mlt = callPackage ../development/libraries/mlt/qt-5.nix { + ffmpeg = ffmpeg_2; + }; + + openbr = callPackage ../development/libraries/openbr { }; + + phonon = callPackage ../development/libraries/phonon { + withQt5 = true; + }; + + phonon-backend-gstreamer = callPackage ../development/libraries/phonon/backends/gstreamer.nix { + withQt5 = true; + }; + + phonon-backend-vlc = callPackage ../development/libraries/phonon/backends/vlc.nix { }; + + polkit-qt = callPackage ../development/libraries/polkit-qt-1/qt-5.nix { }; + + poppler = callPackage ../development/libraries/poppler { + lcms = lcms2; + qt5Support = true; + suffix = "qt5"; + }; + + qca-qt5 = callPackage ../development/libraries/qca-qt5 { }; + + qmltermwidget = callPackage ../development/libraries/qmltermwidget { + inherit (darwin.apple_sdk.libs) utmp; + }; + qmlbox2d = libsForQt5.callPackage ../development/libraries/qmlbox2d { }; + + qscintilla = callPackage ../development/libraries/qscintilla { + withQt5 = true; + }; + + qtutilities = callPackage ../development/libraries/qtutilities { }; + + qtinstaller = callPackage ../development/libraries/qtinstaller { }; + + qtkeychain = callPackage ../development/libraries/qtkeychain { + withQt5 = true; + }; + + qtstyleplugins = callPackage ../development/libraries/qtstyleplugins { }; + + qtstyleplugin-kvantum = libsForQt5.callPackage ../development/libraries/qtstyleplugin-kvantum { }; + + quazip = callPackage ../development/libraries/quazip { }; + + qwt = callPackage ../development/libraries/qwt/6.nix { }; + + telepathy = callPackage ../development/libraries/telepathy/qt { }; + + vlc = callPackage ../applications/video/vlc {}; + + qtwebkit-plugins = callPackage ../development/libraries/qtwebkit-plugins { }; + + }; + + qtEnv = qt5.env; + qt5Full = qt5.full; + + qtkeychain = callPackage ../development/libraries/qtkeychain { }; + + qtpbfimageplugin = libsForQt5.callPackage ../development/libraries/qtpbfimageplugin { }; + + qtscriptgenerator = callPackage ../development/libraries/qtscriptgenerator { }; + + quesoglc = callPackage ../development/libraries/quesoglc { }; + + quickder = callPackage ../development/libraries/quickder {}; + + quicksynergy = callPackage ../applications/misc/quicksynergy { }; + + qwt = callPackage ../development/libraries/qwt {}; + + qwt6_qt4 = callPackage ../development/libraries/qwt/6_qt4.nix { + inherit (darwin.apple_sdk.frameworks) AGL; + }; + + qxt = callPackage ../development/libraries/qxt {}; + + rabbitmq-c = callPackage ../development/libraries/rabbitmq-c {}; + + range-v3 = callPackage ../development/libraries/range-v3 {}; + + rabbitmq-java-client = callPackage ../development/libraries/rabbitmq-java-client {}; + + rapidcheck = callPackage ../development/libraries/rapidcheck {}; + + rapidjson = callPackage ../development/libraries/rapidjson {}; + + rapidxml = callPackage ../development/libraries/rapidxml {}; + + raul = callPackage ../development/libraries/audio/raul { }; + + readline = readline6; + readline6 = readline63; + + readline5 = callPackage ../development/libraries/readline/5.x.nix { }; + + readline62 = callPackage ../development/libraries/readline/6.2.nix { }; + + readline63 = callPackage ../development/libraries/readline/6.3.nix { }; + + readline70 = callPackage ../development/libraries/readline/7.0.nix { }; + + readline80 = callPackage ../development/libraries/readline/8.0.nix { }; + + readosm = callPackage ../development/libraries/readosm { }; + + lambdabot = callPackage ../development/tools/haskell/lambdabot { + haskellLib = haskell.lib; + }; + + lambda-mod-zsh-theme = callPackage ../shells/zsh/lambda-mod-zsh-theme { }; + + leksah = throw ("To use leksah, refer to the instructions in " + + "https://github.com/leksah/leksah."); + + libgme = callPackage ../development/libraries/audio/libgme { }; + + librdf_raptor = callPackage ../development/libraries/librdf/raptor.nix { }; + + librdf_raptor2 = callPackage ../development/libraries/librdf/raptor2.nix { }; + + librdf_rasqal = callPackage ../development/libraries/librdf/rasqal.nix { }; + + librdf_redland = callPackage ../development/libraries/librdf/redland.nix { }; + redland = librdf_redland; # added 2018-04-25 + + librdf = callPackage ../development/libraries/librdf { }; + liblrdf = librdf; # added 2018-04-25 + + libsmf = callPackage ../development/libraries/audio/libsmf { }; + + lilv = callPackage ../development/libraries/audio/lilv { }; + + lv2 = callPackage ../development/libraries/audio/lv2 { }; + lv2Unstable = callPackage ../development/libraries/audio/lv2/unstable.nix { }; + + lvtk = callPackage ../development/libraries/audio/lvtk { }; + + patchwork = callPackage ../applications/networking/ssb/patchwork { }; + + qradiolink = callPackage ../applications/radio/qradiolink { }; + + qrupdate = callPackage ../development/libraries/qrupdate { }; + + qgnomeplatform = libsForQt5.callPackage ../development/libraries/qgnomeplatform { }; + + resolv_wrapper = callPackage ../development/libraries/resolv_wrapper { }; + + rhino = callPackage ../development/libraries/java/rhino { + javac = jdk; + jvm = jre; + }; + + rlog = callPackage ../development/libraries/rlog { }; + + rocksdb = callPackage ../development/libraries/rocksdb { }; + + rocksdb_lite = rocksdb.override { enableLite = true; }; + + rotate-backups = with python3Packages; toPythonApplication rotate-backups; + + rote = callPackage ../development/libraries/rote { }; + + ronn = callPackage ../development/tools/ronn { }; + + rshell = python3.pkgs.callPackage ../development/tools/rshell { }; + + rttr = callPackage ../development/libraries/rttr { }; + + rubberband = callPackage ../development/libraries/rubberband { + inherit (vamp) vampSDK; + }; + + sad = callPackage ../applications/science/logic/sad { }; + + safefile = callPackage ../development/libraries/safefile {}; + + sbc = callPackage ../development/libraries/sbc { }; + + schroedinger = callPackage ../development/libraries/schroedinger { }; + + SDL = callPackage ../development/libraries/SDL ({ + inherit (darwin.apple_sdk.frameworks) OpenGL CoreAudio CoreServices AudioUnit Kernel Cocoa; + } // lib.optionalAttrs stdenv.hostPlatform.isAndroid { + # libGLU doesn’t work with Android’s SDL + libGLU = null; + }); + + SDL_sixel = callPackage ../development/libraries/SDL_sixel { }; + + SDL_gfx = callPackage ../development/libraries/SDL_gfx { }; + + SDL_gpu = callPackage ../development/libraries/SDL_gpu { }; + + SDL_image = callPackage ../development/libraries/SDL_image { }; + + SDL_mixer = callPackage ../development/libraries/SDL_mixer { }; + + SDL_net = callPackage ../development/libraries/SDL_net { }; + + SDL_sound = callPackage ../development/libraries/SDL_sound { }; + + SDL_stretch= callPackage ../development/libraries/SDL_stretch { }; + + SDL_ttf = callPackage ../development/libraries/SDL_ttf { }; + + SDL2 = callPackage ../development/libraries/SDL2 { + inherit (darwin.apple_sdk.frameworks) AudioUnit Cocoa CoreAudio CoreServices ForceFeedback OpenGL; + }; + + SDL2_image = callPackage ../development/libraries/SDL2_image { + inherit (darwin.apple_sdk.frameworks) Foundation; + }; + + SDL2_mixer = callPackage ../development/libraries/SDL2_mixer { + inherit (darwin.apple_sdk.frameworks) CoreServices AudioUnit AudioToolbox; + }; + + SDL2_net = callPackage ../development/libraries/SDL2_net { }; + + SDL2_gfx = callPackage ../development/libraries/SDL2_gfx { }; + + SDL2_ttf = callPackage ../development/libraries/SDL2_ttf { }; + + sdnotify-wrapper = skawarePackages.sdnotify-wrapper; + + sblim-sfcc = callPackage ../development/libraries/sblim-sfcc {}; + + selinux-sandbox = callPackage ../os-specific/linux/selinux-sandbox { }; + + seasocks = callPackage ../development/libraries/seasocks { }; + + serd = callPackage ../development/libraries/serd {}; + + serf = callPackage ../development/libraries/serf {}; + + sfsexp = callPackage ../development/libraries/sfsexp {}; + + shhmsg = callPackage ../development/libraries/shhmsg { }; + + shhopt = callPackage ../development/libraries/shhopt { }; + + graphite2 = callPackage ../development/libraries/silgraphite/graphite2.nix {}; + + simavr = callPackage ../development/tools/simavr { + avrgcc = pkgsCross.avr.buildPackages.gcc; + avrlibc = pkgsCross.avr.libcCross; + inherit (darwin.apple_sdk.frameworks) GLUT; + }; + + simgear = callPackage ../development/libraries/simgear { }; + + simp_le = callPackage ../tools/admin/simp_le { }; + + simpleitk = callPackage ../development/libraries/simpleitk { lua = lua51Packages.lua; }; + + sfml = callPackage ../development/libraries/sfml { + inherit (darwin.apple_sdk.frameworks) IOKit Foundation AppKit OpenAL; + }; + csfml = callPackage ../development/libraries/csfml { }; + + shapelib = callPackage ../development/libraries/shapelib { }; + + shibboleth-sp = callPackage ../development/libraries/shibboleth-sp { }; + + skaffold = callPackage ../development/tools/skaffold { }; + + skalibs = skawarePackages.skalibs; + + skawarePackages = recurseIntoAttrs rec { + cleanPackaging = callPackage ../build-support/skaware/clean-packaging.nix { }; + buildPackage = callPackage ../build-support/skaware/build-skaware-package.nix { + inherit cleanPackaging; + }; + + skalibs = callPackage ../development/libraries/skalibs { }; + execline = callPackage ../tools/misc/execline { }; + + s6 = callPackage ../tools/system/s6 { }; + s6-dns = callPackage ../tools/networking/s6-dns { }; + s6-linux-utils = callPackage ../os-specific/linux/s6-linux-utils { }; + s6-networking = callPackage ../tools/networking/s6-networking { }; + s6-portable-utils = callPackage ../tools/misc/s6-portable-utils { }; + s6-rc = callPackage ../tools/system/s6-rc { }; + + nsss = callPackage ../development/libraries/nsss { }; + utmps = callPackage ../development/libraries/utmps { }; + sdnotify-wrapper = callPackage ../os-specific/linux/sdnotify-wrapper { }; + }; + + skydive = callPackage ../tools/networking/skydive { + # XXX: this is failing with Go 1.12. Error is related to cgo, an + # update to this package might fix it. + buildGoPackage = buildGo111Package; + }; + + slang = callPackage ../development/libraries/slang { }; + + slibGuile = callPackage ../development/libraries/slib { + scheme = guile_1_8; + texinfo = texinfo4; # otherwise erros: must be after `@defun' to use `@defunx' + }; + + smpeg = callPackage ../development/libraries/smpeg { }; + + smpeg2 = callPackage ../development/libraries/smpeg2 { }; + + snack = callPackage ../development/libraries/snack { + # optional + }; + + snappy = callPackage ../development/libraries/snappy { }; + + soapyairspy = callPackage ../applications/radio/soapyairspy { }; + + soapybladerf = callPackage ../applications/radio/soapybladerf { }; + + soapyhackrf = callPackage ../applications/radio/soapyhackrf { }; + + soapysdr = callPackage ../applications/radio/soapysdr { inherit (python3Packages) python numpy; }; + + soapyremote = callPackage ../applications/radio/soapyremote { }; + + soapysdr-with-plugins = callPackage ../applications/radio/soapysdr { + inherit (python3Packages) python numpy; + extraPackages = [ + limesuite + soapyairspy + soapybladerf + soapyhackrf + soapyremote + soapyrtlsdr + soapyuhd + ]; + }; + + soapyrtlsdr = callPackage ../applications/radio/soapyrtlsdr { }; + + soapyuhd = callPackage ../applications/radio/soapyuhd { }; + + socket_wrapper = callPackage ../development/libraries/socket_wrapper { }; + + sofia_sip = callPackage ../development/libraries/sofia-sip { }; + + soil = callPackage ../development/libraries/soil { }; + + sonic = callPackage ../development/libraries/sonic { }; + + soprano = callPackage ../development/libraries/soprano { }; + + soqt = callPackage ../development/libraries/soqt { }; + + sord = callPackage ../development/libraries/sord {}; + + soundtouch = callPackage ../development/libraries/soundtouch {}; + + spandsp = callPackage ../development/libraries/spandsp {}; + + spaceship-prompt = callPackage ../shells/zsh/spaceship-prompt {}; + + spatialite_tools = callPackage ../development/libraries/spatialite-tools { }; + + spdk = callPackage ../development/libraries/spdk { }; + + speechd = callPackage ../development/libraries/speechd { }; + + speech-tools = callPackage ../development/libraries/speech-tools {}; + + speex = callPackage ../development/libraries/speex { + fftw = fftwFloat; + }; + + speexdsp = callPackage ../development/libraries/speexdsp { + fftw = fftwFloat; + }; + + sphinxbase = callPackage ../development/libraries/sphinxbase { }; + + sphinxsearch = callPackage ../servers/search/sphinxsearch { }; + + spice = callPackage ../development/libraries/spice { }; + + spice-gtk = callPackage ../development/libraries/spice-gtk { }; + + spice-protocol = callPackage ../development/libraries/spice-protocol { }; + + spice-up = callPackage ../applications/office/spice-up { }; + + sratom = callPackage ../development/libraries/audio/sratom { }; + + srm = callPackage ../tools/security/srm { }; + + srt = callPackage ../development/libraries/srt { }; + + srtp = callPackage ../development/libraries/srtp { + libpcap = if stdenv.isLinux then libpcap else null; + }; + + stb = callPackage ../development/libraries/stb { }; + + stxxl = callPackage ../development/libraries/stxxl { parallel = true; }; + + sqlite = lowPrio (callPackage ../development/libraries/sqlite { }); + + sqlite-analyzer = lowPrio (callPackage ../development/libraries/sqlite/analyzer.nix { }); + + sqlar = callPackage ../development/libraries/sqlite/sqlar.nix { }; + + sqlite-interactive = appendToName "interactive" (sqlite.override { interactive = true; }).bin; + + sqlite-jdbc = callPackage ../servers/sql/sqlite/jdbc { }; + + sqlite-replication = sqlite.overrideAttrs (oldAttrs: rec { + name = "sqlite-${version}"; + version = "3.27.2+replication3"; + src = pkgs.fetchFromGitHub { + owner = "CanonicalLtd"; + repo = "sqlite"; + rev = "version-${version}"; + sha256 = "1aw1naa5y25ial251f74h039pgcz92p4b3994jvfzqpjlz06qwvw"; + }; + nativeBuildInputs = [ pkgs.tcl ]; + configureFlags = oldAttrs.configureFlags ++ [ + "--enable-replication" + "--disable-amalgamation" + "--disable-tcl" + ]; + preConfigure = '' + echo "D 2019-03-09T15:45:46" > manifest + echo -n "8250984a368079bb1838d48d99f8c1a6282e00bc" > manifest.uuid + ''; + }); + + dqlite = callPackage ../development/libraries/dqlite { }; + + sqlcipher = lowPrio (callPackage ../development/libraries/sqlcipher { + readline = null; + ncurses = null; + }); + + standardnotes = callPackage ../applications/editors/standardnotes { }; + + stfl = callPackage ../development/libraries/stfl { }; + + stlink = callPackage ../development/tools/misc/stlink { + # The Darwin build of stlink explicitly refers to static libusb. + libusb1 = if stdenv.isDarwin then libusb1.override { withStatic = true; } else libusb1; + }; + + steghide = callPackage ../tools/security/steghide {}; + + stlport = callPackage ../development/libraries/stlport { }; + + streamlink = callPackage ../applications/video/streamlink { pythonPackages = python3Packages; }; + + strigi = callPackage ../development/libraries/strigi { clucene_core = clucene_core_2; }; + + subdl = callPackage ../applications/video/subdl { }; + + subtitleeditor = callPackage ../applications/video/subtitleeditor { enchant = enchant1; }; + + suil = callPackage ../development/libraries/audio/suil { }; + + suil-qt5 = suil.override { + withQt4 = false; + withQt5 = true; + }; + suil-qt4 = suil.override { + withQt4 = true; + withQt5 = false; + }; + + sundials = callPackage ../development/libraries/sundials { }; + + sutils = callPackage ../tools/misc/sutils { }; + + svrcore = callPackage ../development/libraries/svrcore { }; + + swiftclient = python3.pkgs.callPackage ../tools/admin/swiftclient { }; + + sword = callPackage ../development/libraries/sword { }; + + biblesync = callPackage ../development/libraries/biblesync { }; + + szip = callPackage ../development/libraries/szip { }; + + t1lib = callPackage ../development/libraries/t1lib { }; + + tachyon = callPackage ../development/libraries/tachyon { + inherit (darwin.apple_sdk.frameworks) Carbon; + }; + + taglib = callPackage ../development/libraries/taglib { }; + taglib_1_9 = callPackage ../development/libraries/taglib/1.9.nix { }; + + taglib_extras = callPackage ../development/libraries/taglib-extras { }; + + taglib-sharp = callPackage ../development/libraries/taglib-sharp { }; + + talloc = callPackage ../development/libraries/talloc { + python = buildPackages.python2; + }; + + tclap = callPackage ../development/libraries/tclap {}; + + tcllib = callPackage ../development/libraries/tcllib { }; + + tcltls = callPackage ../development/libraries/tcltls { + openssl = openssl_1_0_2; + }; + + tclx = callPackage ../development/libraries/tclx { }; + + ntdb = callPackage ../development/libraries/ntdb { + python = python2; + }; + + tdb = callPackage ../development/libraries/tdb {}; + + tdlib = callPackage ../development/libraries/tdlib { }; + + tecla = callPackage ../development/libraries/tecla { }; + + tectonic = callPackage ../tools/typesetting/tectonic { + harfbuzz = harfbuzzFull; + }; + + tepl = callPackage ../development/libraries/tepl { }; + + telepathy-glib = callPackage ../development/libraries/telepathy/glib { }; + + telepathy-farstream = callPackage ../development/libraries/telepathy/farstream {}; + + telepathy-qt = callPackage ../development/libraries/telepathy/qt { qtbase = qt4; }; + + termbox = callPackage ../development/libraries/termbox { }; + + tevent = callPackage ../development/libraries/tevent { + python = python2; + }; + + tet = callPackage ../development/tools/misc/tet { }; + + theft = callPackage ../development/libraries/theft { }; + + thrift = callPackage ../development/libraries/thrift { + inherit (pythonPackages) twisted; + }; + + thrift-0_10 = callPackage ../development/libraries/thrift/0.10.nix { + inherit (pythonPackages) twisted; + }; + + tidyp = callPackage ../development/libraries/tidyp { }; + + tinyxml = tinyxml2; + + tinyxml2 = callPackage ../development/libraries/tinyxml/2.6.2.nix { }; + + tinyxml-2 = callPackage ../development/libraries/tinyxml-2 { }; + + tiscamera = callPackage ../os-specific/linux/tiscamera { }; + + tivodecode = callPackage ../applications/video/tivodecode { }; + + tix = callPackage ../development/libraries/tix { }; + + tk = tk-8_6; + + tk-8_6 = callPackage ../development/libraries/tk/8.6.nix { }; + tk-8_5 = callPackage ../development/libraries/tk/8.5.nix { tcl = tcl-8_5; }; + + tnt = callPackage ../development/libraries/tnt { }; + + tntnet = callPackage ../development/libraries/tntnet { }; + + tntdb = callPackage ../development/libraries/tntdb { }; + + kyotocabinet = callPackage ../development/libraries/kyotocabinet { }; + + tokyocabinet = callPackage ../development/libraries/tokyo-cabinet { }; + + tokyotyrant = callPackage ../development/libraries/tokyo-tyrant { }; + + torch = callPackage ../development/libraries/torch { + openblas = openblasCompat; + }; + + torch-hdf5 = callPackage ../development/libraries/torch-hdf5 {}; + + totem-pl-parser = callPackage ../development/libraries/totem-pl-parser { }; + + tpm2-tss = callPackage ../development/libraries/tpm2-tss { }; + + tremor = callPackage ../development/libraries/tremor { }; + + twolame = callPackage ../development/libraries/twolame { }; + + udns = callPackage ../development/libraries/udns { }; + + uid_wrapper = callPackage ../development/libraries/uid_wrapper { }; + + umockdev = callPackage ../development/libraries/umockdev { + vala = vala_0_40; + }; + + unconvert = callPackage ../development/tools/unconvert { }; + + unibilium = callPackage ../development/libraries/unibilium { }; + + unicap = callPackage ../development/libraries/unicap {}; + + unicon-lang = callPackage ../development/interpreters/unicon-lang {}; + + tsocks = callPackage ../development/libraries/tsocks { }; + + unixODBC = callPackage ../development/libraries/unixODBC { }; + + unixODBCDrivers = recurseIntoAttrs (callPackages ../development/libraries/unixODBCDrivers {}); + + ustr = callPackage ../development/libraries/ustr { }; + + usbredir = callPackage ../development/libraries/usbredir { + libusb = libusb1; + }; + + uthash = callPackage ../development/libraries/uthash { }; + + utmps = skawarePackages.utmps; + + ucommon = ucommon_openssl; + + ucommon_openssl = callPackage ../development/libraries/ucommon { + gnutls = null; + openssl = openssl_1_0_2; + }; + + ucommon_gnutls = lowPrio (ucommon.override { + openssl = null; + zlib = null; + gnutls = gnutls; + }); + + # 3.14 is needed for R V8 module in ../development/r-modules/default.nix + v8_3_14 = callPackage ../development/libraries/v8/3.14.nix { + inherit (python2Packages) python gyp; + cctools = darwin.cctools; + stdenv = gcc5Stdenv; + }; + + v8_3_16_14 = callPackage ../development/libraries/v8/3.16.14.nix { + inherit (python2Packages) python gyp; + cctools = darwin.cctools; + stdenv = if stdenv.isDarwin then stdenv else gcc5Stdenv; + }; + + v8_5_x = callPackage ../development/libraries/v8/5_x.nix ({ + inherit (python2Packages) python gyp; + icu = icu58; # v8-5.4.232 fails against icu4c-59.1 + } // lib.optionalAttrs stdenv.isLinux { + # doesn't build with gcc7 + stdenv = gcc6Stdenv; + }); + + v8_6_x = v8; + v8 = callPackage ../development/libraries/v8 { + inherit (python2Packages) python; + } // lib.optionalAttrs stdenv.isLinux { + # doesn't build with gcc7 + stdenv = gcc6Stdenv; + }; + + vaapiIntel = callPackage ../development/libraries/vaapi-intel { }; + + vaapi-intel-hybrid = callPackage ../development/libraries/vaapi-intel-hybrid { }; + + vaapiVdpau = callPackage ../development/libraries/vaapi-vdpau { }; + + vale = callPackage ../tools/text/vale { }; + + vamp = callPackage ../development/libraries/audio/vamp { }; + + vc = callPackage ../development/libraries/vc { }; + + vc_0_7 = callPackage ../development/libraries/vc/0.7.nix { }; + + vcdimager = callPackage ../development/libraries/vcdimager { }; + + vcg = callPackage ../development/libraries/vcg { }; + + vid-stab = callPackage ../development/libraries/vid-stab { }; + + vigra = callPackage ../development/libraries/vigra { }; + + vlock = callPackage ../misc/screensavers/vlock { }; + + vmime = callPackage ../development/libraries/vmime { }; + + vrb = callPackage ../development/libraries/vrb { }; + + vrpn = callPackage ../development/libraries/vrpn { }; + + vsqlite = callPackage ../development/libraries/vsqlite { }; + + vte = callPackage ../development/libraries/vte { }; + + vte_290 = callPackage ../development/libraries/vte/2.90.nix { }; + + vte-ng = callPackage ../development/libraries/vte/ng.nix { }; + + vtk = callPackage ../development/libraries/vtk { + inherit (darwin) libobjc; + inherit (darwin.apple_sdk.libs) xpc; + inherit (darwin.apple_sdk.frameworks) Cocoa CoreServices DiskArbitration + IOKit CFNetwork Security ApplicationServices + CoreText IOSurface ImageIO OpenGL GLUT; + }; + + vulkan-headers = callPackage ../development/libraries/vulkan-headers { }; + vulkan-loader = callPackage ../development/libraries/vulkan-loader { }; + vulkan-tools = callPackage ../tools/graphics/vulkan-tools { }; + vulkan-validation-layers = callPackage ../development/tools/vulkan-validation-layers { + glslang = (glslang.override { + spirv-tools = spirv-tools.overrideAttrs (_: { + src = fetchFromGitHub { + owner = "KhronosGroup"; + repo = "SPIRV-Tools"; + rev = "26c1b8878315a7a5c188df45e0bc236bb222b698"; + sha256 = "1q76vaqwxf4q2l4rd7j2p2jqgcqpys0m235drzx0drkn2qd50n1b"; + }; + }); + spirv-headers = spirv-tools.overrideAttrs (_: { + src = fetchFromGitHub { + owner = "KhronosGroup"; + repo = "SPIRV-Headers"; + rev = "2434b89345a50c018c84f42a310b0fad4f3fd94f"; + sha256 = "1m902q1alm0rbh69zlskkx4n453xijijp9mf3wzwphi2j36gygwm"; + }; + }); + }).overrideAttrs (_: { + src = fetchFromGitHub { + owner = "KhronosGroup"; + repo = "glslang"; + rev = "e06c7e9a515b716c731bda13f507546f107775d1"; + sha256 = "04y4dd1cqdkd4qffmhgmg3agf9j07ii2w38vpp4jw53ir818bqdq"; + }; + }); + }; + + vtkWithQt4 = vtk.override { qtLib = qt4; }; + + vxl = callPackage ../development/libraries/vxl { + libpng = libpng12; + stdenv = gcc6Stdenv; # upstream code incompatible with gcc7 + }; + + wavpack = callPackage ../development/libraries/wavpack { }; + + wayland = callPackage ../development/libraries/wayland { }; + + wayland_1_9 = callPackage ../development/libraries/wayland/1.9.nix { }; + + wayland-protocols = callPackage ../development/libraries/wayland/protocols.nix { }; + + waylandpp = callPackage ../development/libraries/waylandpp { }; + + wcslib = callPackage ../development/libraries/wcslib { }; + + webkitgtk = callPackage ../development/libraries/webkitgtk { + harfbuzz = harfbuzzFull; + inherit (gst_all_1) gst-plugins-base gst-plugins-bad; + stdenv = gcc6Stdenv; + }; + + webkitgtk24x-gtk3 = callPackage ../development/libraries/webkitgtk/2.4.nix { + harfbuzz = harfbuzzFull.override { + icu = icu58; + }; + gst-plugins-base = gst_all_1.gst-plugins-base; + inherit (darwin) libobjc; + }; + + webkitgtk24x-gtk2 = webkitgtk24x-gtk3.override { + withGtk2 = true; + enableIntrospection = false; + }; + + websocketpp = callPackage ../development/libraries/websocket++ { }; + + webrtc-audio-processing = callPackage ../development/libraries/webrtc-audio-processing { }; + + wildmidi = callPackage ../development/libraries/wildmidi { }; + + wiredtiger = callPackage ../development/libraries/wiredtiger { }; + + wt = wt4; + inherit (callPackages ../development/libraries/wt {}) + wt3 + wt4; + + wxGTK = wxGTK28; + + wxGTK28 = callPackage ../development/libraries/wxwidgets/2.8 { + inherit (gnome2) GConf; + }; + + wxGTK29 = callPackage ../development/libraries/wxwidgets/2.9 { + inherit (gnome2) GConf; + inherit (darwin.stubs) setfile; + inherit (darwin.apple_sdk.frameworks) AGL Carbon Cocoa Kernel QuickTime; + }; + + wxGTK30 = callPackage ../development/libraries/wxwidgets/3.0 { + inherit (gnome2) GConf; + inherit (darwin.stubs) setfile; + inherit (darwin.apple_sdk.frameworks) AGL Carbon Cocoa Kernel QTKit; + }; + + wxGTK31 = callPackage ../development/libraries/wxwidgets/3.1 { + inherit (gnome2) GConf; + inherit (darwin.stubs) setfile; + inherit (darwin.apple_sdk.frameworks) AGL Carbon Cocoa Kernel QTKit; + }; + + wxmac = callPackage ../development/libraries/wxwidgets/3.0/mac.nix { + inherit (darwin.apple_sdk.frameworks) AGL Cocoa Kernel; + inherit (darwin.stubs) setfile rez derez; + }; + + wxSVG = callPackage ../development/libraries/wxSVG { + wxGTK = wxGTK30; + }; + + wtk = callPackage ../development/libraries/wtk { }; + + x264 = callPackage ../development/libraries/x264 { }; + + x265 = callPackage ../development/libraries/x265 { }; + + inherit (callPackages ../development/libraries/xapian { }) + xapian_1_2_22 xapian_1_4; + xapian = xapian_1_4; + + xapian-omega = callPackage ../development/libraries/xapian/tools/omega { + libmagic = file; + }; + + xavs = callPackage ../development/libraries/xavs { }; + + Xaw3d = callPackage ../development/libraries/Xaw3d { }; + + xbase = callPackage ../development/libraries/xbase { }; + + xcb-util-cursor = xorg.xcbutilcursor; + xcb-util-cursor-HEAD = callPackage ../development/libraries/xcb-util-cursor/HEAD.nix { }; + + xcbutilxrm = callPackage ../servers/x11/xorg/xcb-util-xrm.nix { }; + + xdo = callPackage ../tools/misc/xdo { }; + + xineLib = callPackage ../development/libraries/xine-lib { }; + + xautolock = callPackage ../misc/screensavers/xautolock { }; + + xercesc = callPackage ../development/libraries/xercesc {}; + + xalanc = callPackage ../development/libraries/xalanc {}; + + xgboost = callPackage ../development/libraries/xgboost { }; + + xgeometry-select = callPackage ../tools/X11/xgeometry-select { }; + + # Avoid using this. It isn't really a wrapper anymore, but we keep the name. + xlibsWrapper = callPackage ../development/libraries/xlibs-wrapper { + packages = [ + freetype fontconfig xorg.xorgproto xorg.libX11 xorg.libXt + xorg.libXft xorg.libXext xorg.libSM xorg.libICE + ]; + }; + + xmlrpc_c = callPackage ../development/libraries/xmlrpc-c { }; + + xmlsec = callPackage ../development/libraries/xmlsec { }; + + xml-security-c = callPackage ../development/libraries/xml-security-c { }; + + xml-tooling-c = callPackage ../development/libraries/xml-tooling-c { }; + + xlslib = callPackage ../development/libraries/xlslib { }; + + xvidcore = callPackage ../development/libraries/xvidcore { }; + + xxHash = callPackage ../development/libraries/xxHash {}; + + xylib = callPackage ../development/libraries/xylib { }; + + yajl = callPackage ../development/libraries/yajl { }; + + yder = callPackage ../development/libraries/yder { }; + + yojimbo = callPackage ../development/libraries/yojimbo { }; + + yubioath-desktop = libsForQt5.callPackage ../applications/misc/yubioath-desktop { }; + + yubico-pam = callPackage ../development/libraries/yubico-pam { }; + + yubico-piv-tool = callPackage ../tools/misc/yubico-piv-tool { }; + + yubikey-manager = callPackage ../tools/misc/yubikey-manager { }; + + yubikey-manager-qt = libsForQt5.callPackage ../tools/misc/yubikey-manager-qt { + pythonPackages = python3Packages; + }; + + yubikey-neo-manager = callPackage ../tools/misc/yubikey-neo-manager { }; + + yubikey-personalization = callPackage ../tools/misc/yubikey-personalization { + libusb = libusb1; + }; + + yubikey-personalization-gui = libsForQt5.callPackage ../tools/misc/yubikey-personalization-gui { }; + + zeitgeist = callPackage ../development/libraries/zeitgeist { }; + + zlib = callPackage ../development/libraries/zlib { }; + + libdynd = callPackage ../development/libraries/libdynd { }; + + zlog = callPackage ../development/libraries/zlog { }; + + zeromq3 = callPackage ../development/libraries/zeromq/3.x.nix {}; + zeromq4 = callPackage ../development/libraries/zeromq/4.x.nix {}; + zeromq = zeromq4; + + cppzmq = callPackage ../development/libraries/cppzmq {}; + + czmq3 = callPackage ../development/libraries/czmq/3.x.nix {}; + czmq4 = callPackage ../development/libraries/czmq/4.x.nix {}; + czmq = czmq4; + + czmqpp = callPackage ../development/libraries/czmqpp { + czmq = czmq3; + }; + + zmqpp = callPackage ../development/libraries/zmqpp { }; + + zig = callPackage ../development/compilers/zig { + llvmPackages = llvmPackages_8; + }; + + zimlib = callPackage ../development/libraries/zimlib { }; + + zita-convolver = callPackage ../development/libraries/audio/zita-convolver { }; + + zita-alsa-pcmi = callPackage ../development/libraries/audio/zita-alsa-pcmi { }; + + zita-resampler = callPackage ../development/libraries/audio/zita-resampler { }; + + zziplib = callPackage ../development/libraries/zziplib { }; + + gsignond = callPackage ../development/libraries/gsignond { + plugins = []; + }; + + gsignondPlugins = { + sasl = callPackage ../development/libraries/gsignond/plugins/sasl.nix { }; + oauth = callPackage ../development/libraries/gsignond/plugins/oauth.nix { }; + lastfm = callPackage ../development/libraries/gsignond/plugins/lastfm.nix { }; + mail = callPackages ../development/libraries/gsignond/plugins/mail.nix { }; + }; + + ### DEVELOPMENT / LIBRARIES / AGDA + + agda = callPackage ../build-support/agda { + glibcLocales = if pkgs.stdenv.isLinux then pkgs.glibcLocales else null; + extension = self : super : { }; + inherit (haskellPackages) Agda; + }; + + agdaBase = callPackage ../development/libraries/agda/agda-base { }; + + agdaIowaStdlib = callPackage ../development/libraries/agda/agda-iowa-stdlib { }; + + agdaPrelude = callPackage ../development/libraries/agda/agda-prelude { }; + + AgdaStdlib = callPackage ../development/libraries/agda/agda-stdlib { + inherit (haskellPackages) ghcWithPackages; + }; + + AgdaSheaves = callPackage ../development/libraries/agda/Agda-Sheaves { }; + + bitvector = callPackage ../development/libraries/agda/bitvector { }; + + categories = callPackage ../development/libraries/agda/categories { }; + + pretty = callPackage ../development/libraries/agda/pretty { }; + + TotalParserCombinators = callPackage ../development/libraries/agda/TotalParserCombinators { }; + + ### DEVELOPMENT / LIBRARIES / JAVA + + commonsBcel = callPackage ../development/libraries/java/commons/bcel { }; + + commonsBsf = callPackage ../development/libraries/java/commons/bsf { }; + + commonsCompress = callPackage ../development/libraries/java/commons/compress { }; + + commonsFileUpload = callPackage ../development/libraries/java/commons/fileupload { }; + + commonsLang = callPackage ../development/libraries/java/commons/lang { }; + + commonsLogging = callPackage ../development/libraries/java/commons/logging { }; + + commonsIo = callPackage ../development/libraries/java/commons/io { }; + + commonsMath = callPackage ../development/libraries/java/commons/math { }; + + fastjar = callPackage ../development/tools/java/fastjar { }; + + httpunit = callPackage ../development/libraries/java/httpunit { }; + + gwtdragdrop = callPackage ../development/libraries/java/gwt-dragdrop { }; + + gwtwidgets = callPackage ../development/libraries/java/gwt-widgets { }; + + javaCup = callPackage ../development/libraries/java/cup { }; + + jdom = callPackage ../development/libraries/java/jdom { }; + + jflex = callPackage ../development/libraries/java/jflex { }; + + junit = callPackage ../development/libraries/java/junit { antBuild = releaseTools.antBuild; }; + + junixsocket = callPackage ../development/libraries/java/junixsocket { }; + + jzmq = callPackage ../development/libraries/java/jzmq { }; + + lombok = callPackage ../development/libraries/java/lombok { }; + + lucene = callPackage ../development/libraries/java/lucene { }; + + lucenepp = callPackage ../development/libraries/lucene++ { + boost = boost155; + }; + + mockobjects = callPackage ../development/libraries/java/mockobjects { }; + + saxonb = saxonb_8_8; + + inherit (callPackages ../development/libraries/java/saxon { }) + saxon + saxonb_8_8 + saxonb_9_1 + saxon-he; + + smack = callPackage ../development/libraries/java/smack { }; + + swt = callPackage ../development/libraries/java/swt { }; + + + ### DEVELOPMENT / LIBRARIES / JAVASCRIPT + + yuicompressor = callPackage ../development/tools/yuicompressor { }; + + ### DEVELOPMENT / BOWER MODULES (JAVASCRIPT) + + buildBowerComponents = callPackage ../development/bower-modules/generic { }; + + ### DEVELOPMENT / GO MODULES + + buildGo110Package = callPackage ../development/go-packages/generic { + go = buildPackages.go_1_10; + }; + buildGo111Package = callPackage ../development/go-packages/generic { + go = buildPackages.go_1_11; + }; + buildGo112Package = callPackage ../development/go-packages/generic { + go = buildPackages.go_1_12; + }; + + buildGoPackage = buildGo112Package; + + buildGo111Module = callPackage ../development/go-modules/generic { + go = buildPackages.go_1_11; + }; + + buildGo112Module = callPackage ../development/go-modules/generic { + go = buildPackages.go_1_12; + }; + + buildGoModule = buildGo112Module; + + go2nix = callPackage ../development/tools/go2nix { }; + + leaps = callPackage ../development/tools/leaps { }; + + vgo2nix = callPackage ../development/tools/vgo2nix { }; + + ws = callPackage ../development/tools/ws { }; + + ### DEVELOPMENT / JAVA MODULES + + javaPackages = recurseIntoAttrs (callPackage ./java-packages.nix { }); + + ### DEVELOPMENT / LISP MODULES + + asdf = callPackage ../development/lisp-modules/asdf { + texLive = null; + }; + + # QuickLisp minimal version + asdf_2_26 = callPackage ../development/lisp-modules/asdf/2.26.nix { + texLive = null; + }; + # Currently most popular + asdf_3_1 = callPackage ../development/lisp-modules/asdf/3.1.nix { + texLive = null; + }; + + clwrapperFunction = callPackage ../development/lisp-modules/clwrapper; + + wrapLisp = lisp: clwrapperFunction { inherit lisp; }; + + lispPackagesFor = clwrapper: callPackage ../development/lisp-modules/lisp-packages.nix { + inherit clwrapper; + }; + + lispPackages = recurseIntoAttrs (quicklispPackages_asdf_3_1 // + lispPackagesFor ((wrapLisp sbcl).override { asdf = asdf_3_1; })); + + quicklispPackagesFor = clwrapper: callPackage ../development/lisp-modules/quicklisp-to-nix.nix { + inherit clwrapper; + }; + quicklispPackagesClisp = dontRecurseIntoAttrs (quicklispPackagesFor (wrapLisp clisp)); + quicklispPackagesSBCL = dontRecurseIntoAttrs (quicklispPackagesFor (wrapLisp sbcl)); + quicklispPackages = quicklispPackagesSBCL; + quicklispPackages_asdf_3_1 = quicklispPackagesFor + ((wrapLisp sbcl).override { asdf = asdf_3_1; }); + + ### DEVELOPMENT / PERL MODULES + + perlInterpreters = callPackages ../development/interpreters/perl {}; + inherit (perlInterpreters) perl528 perl530 perldevel; + + perl528Packages = recurseIntoAttrs perl528.pkgs; + perl530Packages = recurseIntoAttrs perl530.pkgs; + perldevelPackages = perldevel.pkgs; + + perl = perl528; + perlPackages = perl528Packages; + + ack = perlPackages.ack; + + perlcritic = perlPackages.PerlCritic; + + sqitchPg = callPackage ../development/tools/misc/sqitch { + name = "sqitch-pg"; + databaseModule = perlPackages.DBDPg; + sqitchModule = perlPackages.AppSqitch; + }; + + ### DEVELOPMENT / R MODULES + + R = callPackage ../applications/science/math/R { + # TODO: split docs into a separate output + texLive = texlive.combine { + inherit (texlive) scheme-small inconsolata helvetic texinfo fancyvrb cm-super; + }; + openblas = openblasCompat; + withRecommendedPackages = false; + inherit (darwin.apple_sdk.frameworks) Cocoa Foundation; + inherit (darwin) libobjc; + }; + + rWrapper = callPackage ../development/r-modules/wrapper.nix { + recommendedPackages = with rPackages; [ + boot class cluster codetools foreign KernSmooth lattice MASS + Matrix mgcv nlme nnet rpart spatial survival + ]; + # Override this attribute to register additional libraries. + packages = []; + }; + + rstudioWrapper = libsForQt5.callPackage ../development/r-modules/wrapper-rstudio.nix { + recommendedPackages = with rPackages; [ + boot class cluster codetools foreign KernSmooth lattice MASS + Matrix mgcv nlme nnet rpart spatial survival + ]; + # Override this attribute to register additional libraries. + packages = []; + }; + + rPackages = dontRecurseIntoAttrs (callPackage ../development/r-modules { + overrides = (config.rPackageOverrides or (p: {})) pkgs; + }); + + ### SERVERS + + _389-ds-base = callPackage ../servers/ldap/389 { + kerberos = libkrb5; + }; + + rdf4store = callPackage ../servers/http/4store { }; + + apacheHttpd_2_4 = callPackage ../servers/http/apache-httpd/2.4.nix { }; + apacheHttpd = pkgs.apacheHttpd_2_4; + + apacheHttpdPackagesFor = apacheHttpd: self: let callPackage = newScope self; in { + inherit apacheHttpd; + + mod_auth_mellon = callPackage ../servers/http/apache-modules/mod_auth_mellon { }; + + mod_dnssd = callPackage ../servers/http/apache-modules/mod_dnssd { }; + + mod_evasive = callPackage ../servers/http/apache-modules/mod_evasive { }; + + mod_perl = callPackage ../servers/http/apache-modules/mod_perl { }; + + mod_fastcgi = callPackage ../servers/http/apache-modules/mod_fastcgi { }; + + mod_python = callPackage ../servers/http/apache-modules/mod_python { }; + + mod_wsgi = callPackage ../servers/http/apache-modules/mod_wsgi { }; + + php = pkgs.php.override { inherit apacheHttpd; }; + + subversion = pkgs.subversion.override { httpServer = true; inherit apacheHttpd; }; + }; + + apacheHttpdPackages_2_4 = dontRecurseIntoAttrs (apacheHttpdPackagesFor pkgs.apacheHttpd_2_4 pkgs.apacheHttpdPackages_2_4); + apacheHttpdPackages = apacheHttpdPackages_2_4; + + appdaemon = callPackage ../servers/home-assistant/appdaemon.nix { }; + + archiveopteryx = callPackage ../servers/mail/archiveopteryx { }; + + atlassian-confluence = callPackage ../servers/atlassian/confluence.nix { }; + atlassian-crowd = callPackage ../servers/atlassian/crowd.nix { }; + atlassian-jira = callPackage ../servers/atlassian/jira.nix { }; + + cadvisor = callPackage ../servers/monitoring/cadvisor { }; + + cassandra_2_1 = callPackage ../servers/nosql/cassandra/2.1.nix { }; + cassandra_2_2 = callPackage ../servers/nosql/cassandra/2.2.nix { }; + cassandra_3_0 = callPackage ../servers/nosql/cassandra/3.0.nix { }; + cassandra_3_11 = callPackage ../servers/nosql/cassandra/3.11.nix { }; + cassandra = cassandra_3_11; + + apache-jena = callPackage ../servers/nosql/apache-jena/binary.nix { + java = jdk; + }; + + apache-jena-fuseki = callPackage ../servers/nosql/apache-jena/fuseki-binary.nix { + java = jdk; + }; + + apcupsd = callPackage ../servers/apcupsd { }; + + inherit (callPackages ../servers/asterisk { }) + asterisk asterisk-stable asterisk-lts + asterisk_13 asterisk_15 asterisk_16; + + sabnzbd = callPackage ../servers/sabnzbd { }; + + bftpd = callPackage ../servers/ftp/bftpd {}; + + bind = callPackage ../servers/dns/bind { }; + dnsutils = bind.dnsutils; + + inherit (callPackages ../servers/bird { }) + bird bird6 bird2; + + bosun = callPackage ../servers/monitoring/bosun { }; + + cayley = callPackage ../servers/cayley { }; + + charybdis = callPackage ../servers/irc/charybdis { }; + + clamsmtp = callPackage ../servers/mail/clamsmtp { }; + + clickhouse = callPackage ../servers/clickhouse { + # clickhouse doesn't build on llvm8. + inherit (llvmPackages_7) clang-unwrapped lld llvm; + }; + + couchdb = callPackage ../servers/http/couchdb { + spidermonkey = spidermonkey_1_8_5; + sphinx = python27Packages.sphinx; + erlang = erlangR19; + }; + + couchdb2 = callPackage ../servers/http/couchdb/2.0.0.nix { + spidermonkey = spidermonkey_1_8_5; + erlang = erlangR21; + }; + + couchpotato = callPackage ../servers/couchpotato {}; + + dex-oidc = callPackage ../servers/dex { }; + + doh-proxy = callPackage ../servers/dns/doh-proxy { + python3Packages = python36Packages; + }; + + dgraph = callPackage ../servers/dgraph { }; + + dico = callPackage ../servers/dico { }; + + dict = callPackage ../servers/dict { + libmaa = callPackage ../servers/dict/libmaa.nix {}; + }; + + dictdDBs = recurseIntoAttrs (callPackages ../servers/dict/dictd-db.nix {}); + + dictDBCollector = callPackage ../servers/dict/dictd-db-collector.nix {}; + + diod = callPackage ../servers/diod { lua = lua5_1; }; + + dkimproxy = callPackage ../servers/mail/dkimproxy { }; + + dovecot = callPackage ../servers/mail/dovecot { }; + dovecot_pigeonhole = callPackage ../servers/mail/dovecot/plugins/pigeonhole { }; + + dspam = callPackage ../servers/mail/dspam { }; + + etcd = callPackage ../servers/etcd { }; + + ejabberd = callPackage ../servers/xmpp/ejabberd { }; + + exhibitor = callPackage ../servers/exhibitor { }; + + hyp = callPackage ../servers/http/hyp { }; + + prosody = callPackage ../servers/xmpp/prosody { + # _compat can probably be removed on next minor version after 0.10.0 + lua5 = lua5_2_compat; + withExtraLibs = [ luaPackages.luadbi-sqlite3 ]; + inherit (lua52Packages) luasocket luasec luaexpat luafilesystem luabitop luaevent luadbi; + }; + + biboumi = callPackage ../servers/xmpp/biboumi { }; + + elasticmq = callPackage ../servers/elasticmq { }; + + elasticmq-server-bin = callPackage ../servers/elasticmq-server-bin { }; + + eventstore = callPackage ../servers/nosql/eventstore { + Nuget = dotnetPackages.Nuget; + }; + + exim = callPackage ../servers/mail/exim { }; + + facette = callPackage ../servers/monitoring/facette { }; + + fcgiwrap = callPackage ../servers/fcgiwrap { }; + + felix = callPackage ../servers/felix { }; + + felix_remoteshell = callPackage ../servers/felix/remoteshell.nix { }; + + fingerd_bsd = callPackage ../servers/fingerd/bsd-fingerd { }; + + firebird = callPackage ../servers/firebird { icu = null; stdenv = gcc5Stdenv; }; + firebirdSuper = firebird.override { icu = icu58; superServer = true; stdenv = gcc5Stdenv; }; + + frab = callPackage ../servers/web-apps/frab { }; + + freepops = callPackage ../servers/mail/freepops { }; + + freeradius = callPackage ../servers/freeradius { }; + + freeswitch = callPackage ../servers/sip/freeswitch { + inherit (darwin.apple_sdk.frameworks) SystemConfiguration; + }; + + fusionInventory = callPackage ../servers/monitoring/fusion-inventory { }; + + gatling = callPackage ../servers/http/gatling { }; + + glabels = callPackage ../applications/graphics/glabels { }; + + gnatsd = callPackage ../servers/gnatsd { }; + + gofish = callPackage ../servers/gopher/gofish { }; + + grafana = callPackage ../servers/monitoring/grafana { }; + + grafana-loki = callPackage ../servers/monitoring/loki { }; + + grafana_reporter = callPackage ../servers/monitoring/grafana-reporter { }; + + h2o = callPackage ../servers/http/h2o { }; + + haka = callPackage ../tools/security/haka { }; + + heapster = callPackage ../servers/monitoring/heapster { }; + + hbase = callPackage ../servers/hbase {}; + + headphones = callPackage ../servers/headphones {}; + + hiawatha = callPackage ../servers/http/hiawatha {}; + + home-assistant = callPackage ../servers/home-assistant { }; + + home-assistant-cli = callPackage ../servers/home-assistant/cli.nix { }; + + hydron = callPackage ../servers/hydron { }; + + icingaweb2 = callPackage ../servers/icingaweb2 { }; + icingaweb2Modules = { + theme-april = callPackage ../servers/icingaweb2/theme-april { }; + theme-lsd = callPackage ../servers/icingaweb2/theme-lsd { }; + theme-particles = callPackage ../servers/icingaweb2/theme-particles { }; + theme-snow = callPackage ../servers/icingaweb2/theme-snow { }; + theme-spring = callPackage ../servers/icingaweb2/theme-spring { }; + }; + + ircdHybrid = callPackage ../servers/irc/ircd-hybrid { }; + + jboss = callPackage ../servers/http/jboss { }; + + jboss_mysql_jdbc = callPackage ../servers/http/jboss/jdbc/mysql { }; + + jetty = callPackage ../servers/http/jetty { }; + + knot-dns = callPackage ../servers/dns/knot-dns { }; + knot-resolver = callPackage ../servers/dns/knot-resolver { }; + + rdkafka = callPackage ../development/libraries/rdkafka { }; + + leafnode = callPackage ../servers/news/leafnode { }; + + lighttpd = callPackage ../servers/http/lighttpd { }; + + livepeer = callPackage ../servers/livepeer { }; + + lwan = callPackage ../servers/http/lwan { }; + + labelImg = callPackage ../applications/science/machine-learning/labelimg { }; + + mailman = callPackage ../servers/mail/mailman { }; + + mailman-rss = callPackage ../development/python-modules/mailman-rss { }; + + mattermost = callPackage ../servers/mattermost { }; + matterircd = callPackage ../servers/mattermost/matterircd.nix { }; + matterbridge = callPackage ../servers/matterbridge { }; + + mattermost-desktop = callPackage ../applications/networking/instant-messengers/mattermost-desktop { }; + + mediatomb = callPackage ../servers/mediatomb { }; + + meguca = callPackage ../servers/meguca { + buildGoPackage = buildGo110Package; + }; + + memcached = callPackage ../servers/memcached {}; + + meteor = callPackage ../servers/meteor { }; + + minio = callPackage ../servers/minio { }; + + # Backwards compatibility. + mod_dnssd = pkgs.apacheHttpdPackages.mod_dnssd; + mod_fastcgi = pkgs.apacheHttpdPackages.mod_fastcgi; + mod_python = pkgs.apacheHttpdPackages.mod_python; + mod_wsgi = pkgs.apacheHttpdPackages.mod_wsgi; + + mpd = callPackage ../servers/mpd (config.mpd or {}); + + mpd_clientlib = callPackage ../servers/mpd/clientlib.nix { }; + + mpdscribble = callPackage ../tools/misc/mpdscribble { }; + + mtprotoproxy = python3.pkgs.callPackage ../servers/mtprotoproxy { }; + + micro-httpd = callPackage ../servers/http/micro-httpd { }; + + miniHttpd = callPackage ../servers/http/mini-httpd {}; + + mlmmj = callPackage ../servers/mail/mlmmj { }; + + morty = callPackage ../servers/web-apps/morty { }; + + mullvad-vpn = callPackage ../applications/networking/mullvad-vpn { }; + + mumsi = callPackage ../servers/mumsi { }; + + myserver = callPackage ../servers/http/myserver { }; + + nas = callPackage ../servers/nas { }; + + nats-streaming-server = callPackage ../servers/nats-streaming-server { }; + + neard = callPackage ../servers/neard { }; + + unit = callPackage ../servers/http/unit { + php72 = php72-unit; + php73 = php73-unit; + }; + + nginx = nginxStable; + + nginxStable = callPackage ../servers/http/nginx/stable.nix { + # We don't use `with` statement here on purpose! + # See https://github.com/NixOS/nixpkgs/pull/10474/files#r42369334 + modules = [ nginxModules.rtmp nginxModules.dav nginxModules.moreheaders ]; + }; + + nginxMainline = callPackage ../servers/http/nginx/mainline.nix { + # We don't use `with` statement here on purpose! + # See https://github.com/NixOS/nixpkgs/pull/10474/files#r42369334 + modules = [ nginxModules.dav nginxModules.moreheaders ]; + }; + + nginxModules = callPackage ../servers/http/nginx/modules.nix { }; + + # We should move to dynmaic modules and create a nginxFull package with all modules + nginxShibboleth = nginxStable.override { + modules = [ nginxModules.rtmp nginxModules.dav nginxModules.moreheaders nginxModules.shibboleth ]; + }; + + libmodsecurity = callPackage ../tools/security/libmodsecurity { }; + + ngircd = callPackage ../servers/irc/ngircd { }; + + nix-binary-cache = callPackage ../servers/http/nix-binary-cache {}; + + nix-tour = callPackage ../applications/misc/nix-tour {}; + + nsd = callPackage ../servers/dns/nsd (config.nsd or {}); + + nsq = callPackage ../servers/nsq { }; + + oauth2_proxy = callPackage ../servers/oauth2_proxy { }; + + openafs = callPackage ../servers/openafs/1.6 { tsmbac = null; ncurses = null; }; + openafs_1_8 = callPackage ../servers/openafs/1.8 { tsmbac = null; ncurses = null; }; + + openresty = callPackage ../servers/http/openresty { }; + + opensmtpd = callPackage ../servers/mail/opensmtpd { }; + opensmtpd-extras = callPackage ../servers/mail/opensmtpd/extras.nix { }; + + openxpki = callPackage ../servers/openxpki { }; + + openxr-loader = callPackage ../development/libraries/openxr-loader { }; + + osrm-backend = callPackage ../servers/osrm-backend { }; + + p910nd = callPackage ../servers/p910nd { }; + + petidomo = callPackage ../servers/mail/petidomo { }; + + popa3d = callPackage ../servers/mail/popa3d { }; + + postfix = callPackage ../servers/mail/postfix { }; + + postsrsd = callPackage ../servers/mail/postsrsd { }; + + rmilter = callPackage ../servers/mail/rmilter { }; + + rspamd = callPackage ../servers/mail/rspamd { }; + + pfixtools = callPackage ../servers/mail/postfix/pfixtools.nix { + gperf = gperf_3_0; + }; + pflogsumm = callPackage ../servers/mail/postfix/pflogsumm.nix { }; + + postgrey = callPackage ../servers/mail/postgrey { }; + + pshs = callPackage ../servers/http/pshs { }; + + system-sendmail = lowPrio (callPackage ../servers/mail/system-sendmail { }); + + # PulseAudio daemons + + pulseaudio = callPackage ../servers/pulseaudio { + inherit (darwin.apple_sdk.frameworks) CoreServices AudioUnit Cocoa; + }; + + pulseaudioFull = pulseaudio.override { + x11Support = true; + jackaudioSupport = true; + airtunesSupport = true; + bluetoothSupport = true; + remoteControlSupport = true; + zeroconfSupport = true; + }; + + # libpulse implementations + libpulseaudio-vanilla = pulseaudio.override { + libOnly = true; + }; + + apulse = callPackage ../misc/apulse { }; + + libpressureaudio = callPackage ../misc/apulse/pressureaudio.nix { + libpulseaudio = libpulseaudio-vanilla; # headers only + }; + + libcardiacarrest = callPackage ../misc/libcardiacarrest { + libpulseaudio = libpulseaudio-vanilla; # meta only + }; + + libpulseaudio = libpulseaudio-vanilla; + + pulseeffects = callPackage ../applications/audio/pulseeffects { }; + + tomcat_connectors = callPackage ../servers/http/apache-modules/tomcat-connectors { }; + + pies = callPackage ../servers/pies { }; + + rpcbind = callPackage ../servers/rpcbind { }; + + mariadb = callPackage ../servers/sql/mariadb { + asio = asio_1_10; + # As per mariadb's cmake, "static jemalloc_pic.a can only be used up to jemalloc 4". + # https://jira.mariadb.org/browse/MDEV-15034 + jemalloc = jemalloc450.override ({ disableInitExecTls = true; }); + inherit (darwin) cctools; + inherit (pkgs.darwin.apple_sdk.frameworks) CoreServices; + }; + mysql = mariadb; # TODO: move to aliases.nix + + mongodb = callPackage ../servers/nosql/mongodb { + sasl = cyrus_sasl; + boost = boost160; + openssl = openssl_1_0_2; + inherit (darwin.apple_sdk.frameworks) Security; + }; + + nginx-sso = callPackage ../servers/nginx-sso { }; + + percona-server56 = callPackage ../servers/sql/percona/5.6.x.nix { }; + percona-server = percona-server56; + + riak = callPackage ../servers/nosql/riak/2.2.0.nix { + erlang = erlang_basho_R16B02; + }; + + riak-cs = callPackage ../servers/nosql/riak-cs/2.1.1.nix { + inherit (darwin.apple_sdk.frameworks) Carbon Cocoa; + erlang = erlang_basho_R16B02; + }; + + stanchion = callPackage ../servers/nosql/riak-cs/stanchion.nix { + inherit (darwin.apple_sdk.frameworks) Carbon Cocoa; + erlang = erlang_basho_R16B02; + }; + + influxdb = callPackage ../servers/nosql/influxdb { }; + + mysql57 = callPackage ../servers/sql/mysql/5.7.x.nix { + inherit (darwin) cctools developer_cmds; + inherit (darwin.apple_sdk.frameworks) CoreServices; + boost = boost159; + }; + + mysql80 = callPackage ../servers/sql/mysql/8.0.x.nix { + inherit (darwin) cctools developer_cmds; + inherit (darwin.apple_sdk.frameworks) CoreServices; + boost = boost169; # Configure checks for specific version. + }; + + mysql_jdbc = callPackage ../servers/sql/mysql/jdbc { }; + + mssql_jdbc = callPackage ../servers/sql/mssql/jdbc { }; + + miniflux = callPackage ../servers/miniflux { }; + + nagios = callPackage ../servers/monitoring/nagios { }; + + munin = callPackage ../servers/monitoring/munin { }; + + monitoring-plugins = callPackage ../servers/monitoring/plugins { }; + + inherit (callPackage ../servers/monitoring/plugins/labs_consol_de.nix { }) + check-mssql-health + check-nwc-health + check-ups-health; + + checkSSLCert = callPackage ../servers/monitoring/nagios/plugins/check_ssl_cert.nix { }; + + neo4j = callPackage ../servers/nosql/neo4j { }; + + check-esxi-hardware = callPackage ../servers/monitoring/plugins/esxi.nix {}; + + net_snmp = callPackage ../servers/monitoring/net-snmp { }; + + newrelic-sysmond = callPackage ../servers/monitoring/newrelic-sysmond { }; + + nullidentdmod = callPackage ../servers/identd/nullidentdmod {}; + + riemann = callPackage ../servers/monitoring/riemann { }; + riemann-dash = callPackage ../servers/monitoring/riemann-dash { }; + + oidentd = callPackage ../servers/identd/oidentd { }; + + openfire = callPackage ../servers/xmpp/openfire { }; + + oracleXE = callPackage ../servers/sql/oracle-xe { }; + + softether_4_25 = callPackage ../servers/softether/4.25.nix { openssl = openssl_1_0_2; }; + softether_4_29 = callPackage ../servers/softether/4.29.nix { }; + softether = softether_4_29; + + qboot = pkgsi686Linux.callPackage ../applications/virtualization/qboot { }; + + OVMF = callPackage ../applications/virtualization/OVMF { }; + OVMF-CSM = OVMF.override { csmSupport = true; }; + OVMF-secureBoot = OVMF.override { secureBoot = true; }; + + seabios = callPackage ../applications/virtualization/seabios { }; + + cbfstool = callPackage ../applications/virtualization/cbfstool { }; + + ifdtool = callPackage ../tools/misc/ifdtool { }; + + cbmem = callPackage ../tools/misc/cbmem { }; + + nvramtool = callPackage ../tools/misc/nvramtool { }; + + vmfs-tools = callPackage ../tools/filesystems/vmfs-tools { }; + + pgbouncer = callPackage ../servers/sql/pgbouncer { }; + + pgpool94 = pgpool.override { postgresql = postgresql_9_4; }; + + pgpool = callPackage ../servers/sql/pgpool { + pam = if stdenv.isLinux then pam else null; + libmemcached = null; # Detection is broken upstream + }; + + timescaledb-parallel-copy = callPackage ../development/tools/database/timescaledb-parallel-copy { }; + + timescaledb-tune = callPackage ../development/tools/database/timescaledb-tune { }; + + inherit (import ../servers/sql/postgresql pkgs) + postgresql_9_4 + postgresql_9_5 + postgresql_9_6 + postgresql_10 + postgresql_11 + ; + postgresql = postgresql_9_6.override { this = postgresql; }; + postgresqlPackages = recurseIntoAttrs postgresql.pkgs; + postgresql11Packages = recurseIntoAttrs postgresql_11.pkgs; + + postgresql_jdbc = callPackage ../development/java-modules/postgresql_jdbc { }; + + inherit (callPackage ../servers/monitoring/prometheus { + buildGoPackage = buildGo110Package; + }) prometheus_1; + + inherit (callPackage ../servers/monitoring/prometheus { }) + prometheus_2; + + prom2json = callPackage ../servers/monitoring/prometheus/prom2json.nix { }; + prometheus = prometheus_1; + prometheus-alertmanager = callPackage ../servers/monitoring/prometheus/alertmanager.nix { }; + prometheus-bind-exporter = callPackage ../servers/monitoring/prometheus/bind-exporter.nix { }; + prometheus-blackbox-exporter = callPackage ../servers/monitoring/prometheus/blackbox-exporter.nix { }; + prometheus-collectd-exporter = callPackage ../servers/monitoring/prometheus/collectd-exporter.nix { }; + prometheus-consul-exporter = callPackage ../servers/monitoring/prometheus/consul-exporter.nix { }; + prometheus-dnsmasq-exporter = callPackage ../servers/monitoring/prometheus/dnsmasq-exporter.nix { }; + prometheus-dovecot-exporter = callPackage ../servers/monitoring/prometheus/dovecot-exporter.nix { }; + prometheus-fritzbox-exporter = callPackage ../servers/monitoring/prometheus/fritzbox-exporter.nix { }; + prometheus-haproxy-exporter = callPackage ../servers/monitoring/prometheus/haproxy-exporter.nix { }; + prometheus-json-exporter = callPackage ../servers/monitoring/prometheus/json-exporter.nix { }; + prometheus-mail-exporter = callPackage ../servers/monitoring/prometheus/mail-exporter.nix { }; + prometheus-mesos-exporter = callPackage ../servers/monitoring/prometheus/mesos-exporter.nix { }; + prometheus-minio-exporter = callPackage ../servers/monitoring/prometheus/minio-exporter { }; + prometheus-mysqld-exporter = callPackage ../servers/monitoring/prometheus/mysqld-exporter.nix { }; + prometheus-nginx-exporter = callPackage ../servers/monitoring/prometheus/nginx-exporter.nix { }; + prometheus-node-exporter = callPackage ../servers/monitoring/prometheus/node-exporter.nix { }; + prometheus-openvpn-exporter = callPackage ../servers/monitoring/prometheus/openvpn-exporter.nix { }; + prometheus-postfix-exporter = callPackage ../servers/monitoring/prometheus/postfix-exporter.nix { }; + prometheus-postgres-exporter = callPackage ../servers/monitoring/prometheus/postgres-exporter.nix { }; + prometheus-pushgateway = callPackage ../servers/monitoring/prometheus/pushgateway.nix { }; + prometheus-rabbitmq-exporter = callPackage ../servers/monitoring/prometheus/rabbitmq-exporter.nix { }; + prometheus-snmp-exporter = callPackage ../servers/monitoring/prometheus/snmp-exporter.nix { + buildGoPackage = buildGo110Package; + }; + prometheus-tor-exporter = callPackage ../servers/monitoring/prometheus/tor-exporter.nix { }; + prometheus-statsd-exporter = callPackage ../servers/monitoring/prometheus/statsd-exporter.nix { }; + prometheus-surfboard-exporter = callPackage ../servers/monitoring/prometheus/surfboard-exporter.nix { }; + prometheus-unifi-exporter = callPackage ../servers/monitoring/prometheus/unifi-exporter { }; + prometheus-varnish-exporter = callPackage ../servers/monitoring/prometheus/varnish-exporter.nix { }; + prometheus-jmx-httpserver = callPackage ../servers/monitoring/prometheus/jmx-httpserver.nix { }; + prometheus-wireguard-exporter = callPackage ../servers/monitoring/prometheus/wireguard-exporter.nix { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + prometheus-cpp = callPackage ../development/libraries/prometheus-cpp { }; + + psqlodbc = callPackage ../development/libraries/psqlodbc { }; + + pure-ftpd = callPackage ../servers/ftp/pure-ftpd { }; + + pyIRCt = callPackage ../servers/xmpp/pyIRCt {}; + + pyMAILt = callPackage ../servers/xmpp/pyMAILt {}; + + pypolicyd-spf = python3.pkgs.callPackage ../servers/mail/pypolicyd-spf { }; + + qpid-cpp = callPackage ../servers/amqp/qpid-cpp { + boost = boost155; + inherit (pythonPackages) buildPythonPackage qpid-python; + }; + + quagga = callPackage ../servers/quagga { }; + + rabbitmq-server = callPackage ../servers/amqp/rabbitmq-server { + inherit (darwin.apple_sdk.frameworks) AppKit Carbon Cocoa; + elixir = elixir_1_8; + erlang = erlang_nox; + }; + + radicale1 = callPackage ../servers/radicale/1.x.nix { }; + radicale2 = callPackage ../servers/radicale { }; + + radicale = radicale2; + + rake = callPackage ../development/tools/build-managers/rake { }; + + redis = callPackage ../servers/nosql/redis { }; + + redstore = callPackage ../servers/http/redstore { }; + + restic = callPackage ../tools/backup/restic { }; + + restic-rest-server = callPackage ../tools/backup/restic/rest-server.nix { }; + + restya-board = callPackage ../servers/web-apps/restya-board { }; + + rethinkdb = callPackage ../servers/nosql/rethinkdb { + libtool = darwin.cctools; + }; + + rippled = callPackage ../servers/rippled { + boost = boost167; + }; + + rippled-validator-keys-tool = callPackage ../servers/rippled/validator-keys-tool.nix { + boost = boost167.override { + enableStatic = true; + }; + }; + + roon-server = callPackage ../servers/roon-server { }; + + s6 = skawarePackages.s6; + + s6-rc = skawarePackages.s6-rc; + + supervise = callPackage ../tools/system/supervise { }; + + spamassassin = callPackage ../servers/mail/spamassassin { }; + + deadpixi-sam-unstable = callPackage ../applications/editors/deadpixi-sam { }; + + samba3 = callPackage ../servers/samba/3.x.nix { }; + + samba4 = callPackage ../servers/samba/4.x.nix { + rpcgen = netbsd.rpcgen; + python = python3; + }; + + sambaMaster = callPackage ../servers/samba/master.nix { }; + + samba = samba4; + + # A lightweight Samba 3, useful for non-Linux-based OSes. + samba3_light = lowPrio (samba3.override { + pam = null; + fam = null; + cups = null; + acl = null; + openldap = null; + # libunwind 1.0.1 is not ported to GNU/Hurd. + libunwind = null; + }); + + samba4Full = lowPrio (samba4.override { + enableLDAP = true; + enablePrinting = true; + enableMDNS = true; + enableDomainController = true; + enableRegedit = true; + enableCephFS = true; + enableGlusterFS = true; + }); + + sambaFull = samba4Full; + + sampler = callPackage ../applications/misc/sampler { }; + + shairplay = callPackage ../servers/shairplay { avahi = avahi-compat; }; + + shairport-sync = callPackage ../servers/shairport-sync { }; + + showoff = callPackage ../servers/http/showoff {}; + + serfdom = callPackage ../servers/serf { }; + + seyren = callPackage ../servers/monitoring/seyren { }; + + ruby-zoom = callPackage ../tools/text/ruby-zoom { }; + + sensu = callPackage ../servers/monitoring/sensu { }; + + inherit (callPackages ../servers/monitoring/sensu-go { }) + sensu-go-agent + sensu-go-backend + sensu-go-cli; + + uchiwa = callPackage ../servers/monitoring/uchiwa { }; + + shishi = callPackage ../servers/shishi { + pam = if stdenv.isLinux then pam else null; + # see also openssl, which has/had this same trick + }; + + sickbeard = callPackage ../servers/sickbeard { }; + + sickgear = callPackage ../servers/sickbeard/sickgear.nix { }; + + sickrage = callPackage ../servers/sickbeard/sickrage.nix { }; + + sipcmd = callPackage ../applications/networking/sipcmd { }; + + sipwitch = callPackage ../servers/sip/sipwitch { }; + + slimserver = callPackage ../servers/slimserver { }; + + smcroute = callPackage ../servers/smcroute { }; + + spawn_fcgi = callPackage ../servers/http/spawn-fcgi { }; + + squid = callPackage ../servers/squid { }; + + sslh = callPackage ../servers/sslh { }; + + thttpd = callPackage ../servers/http/thttpd { }; + + storm = callPackage ../servers/computing/storm { }; + + slurm = callPackage ../servers/computing/slurm { gtk2 = null; }; + + slurm-spank-x11 = callPackage ../servers/computing/slurm-spank-x11 { }; + + systemd-journal2gelf = callPackage ../tools/system/systemd-journal2gelf { }; + + syncserver = callPackage ../servers/syncserver { }; + + thanos = callPackage ../servers/monitoring/thanos { }; + + inherit (callPackages ../servers/http/tomcat { }) + tomcat7 + tomcat8 + tomcat85 + tomcat9; + + tomcat_mysql_jdbc = callPackage ../servers/http/tomcat/jdbc/mysql { }; + + torque = callPackage ../servers/computing/torque { }; + + tt-rss = callPackage ../servers/tt-rss { }; + tt-rss-plugin-ff-instagram = callPackage ../servers/tt-rss/plugin-ff-instagram { }; + tt-rss-plugin-tumblr-gdpr = callPackage ../servers/tt-rss/plugin-tumblr-gdpr { }; + tt-rss-plugin-auth-ldap = callPackage ../servers/tt-rss/plugin-auth-ldap { }; + tt-rss-theme-feedly = callPackage ../servers/tt-rss/theme-feedly { }; + + searx = callPackage ../servers/web-apps/searx { }; + + selfoss = callPackage ../servers/web-apps/selfoss { }; + + shaarli = callPackage ../servers/web-apps/shaarli { }; + + shaarli-material = callPackage ../servers/web-apps/shaarli/material-theme.nix { }; + + matomo = callPackage ../servers/web-apps/matomo { }; + + axis2 = callPackage ../servers/http/tomcat/axis2 { }; + + inherit (callPackages ../servers/unifi { }) + unifiLTS + unifiStable + unifiTesting; + unifi = unifiStable; + + virtlyst = libsForQt5.callPackage ../servers/web-apps/virtlyst { }; + + virtuoso6 = callPackage ../servers/sql/virtuoso/6.x.nix { + openssl = openssl_1_0_2; + }; + + virtuoso7 = callPackage ../servers/sql/virtuoso/7.x.nix { + openssl = openssl_1_0_2; + }; + + virtuoso = virtuoso6; + + vsftpd = callPackage ../servers/ftp/vsftpd { }; + + wallabag = callPackage ../servers/web-apps/wallabag { }; + + webmetro = callPackage ../servers/webmetro { }; + + webhook = callPackage ../servers/http/webhook { }; + + winstone = throw "Winstone is not supported anymore. Alternatives are Jetty or Tomcat."; + + xinetd = callPackage ../servers/xinetd { }; + + zookeeper = callPackage ../servers/zookeeper { }; + + zookeeper_mt = callPackage ../development/libraries/zookeeper_mt { }; + + xqilla = callPackage ../development/tools/xqilla { }; + + xquartz = callPackage ../servers/x11/xquartz { }; + + quartz-wm = callPackage ../servers/x11/quartz-wm { + stdenv = clangStdenv; + inherit (darwin.apple_sdk.frameworks) AppKit Foundation; + inherit (darwin.apple_sdk.libs) Xplugin; + }; + + # Use `lib.callPackageWith __splicedPackages` rather than plain `callPackage` + # so as not to have the newly bound xorg items already in scope, which would + # have created a cycle. + xorg = recurseIntoAttrs ((lib.callPackageWith __splicedPackages ../servers/x11/xorg { + }).overrideScope' (lib.callPackageWith __splicedPackages ../servers/x11/xorg/overrides.nix { + inherit (darwin.apple_sdk.frameworks) ApplicationServices Carbon Cocoa; + inherit (darwin.apple_sdk.libs) Xplugin; + inherit (buildPackages.darwin) bootstrap_cmds; + udev = if stdenv.isLinux then udev else null; + libdrm = if stdenv.isLinux then libdrm else null; + abiCompat = config.xorg.abiCompat # `config` because we have no `xorg.override` + or (if stdenv.isDarwin then "1.18" else null); # 1.19 needs fixing on Darwin + }) // { inherit xlibsWrapper; } ); + + xwayland = callPackage ../servers/x11/xorg/xwayland.nix { }; + + yaws = callPackage ../servers/http/yaws { + erlang = erlangR18; + }; + + youtrack = callPackage ../servers/jetbrains/youtrack.nix { }; + + zabbixFor = version: rec { + agent = (callPackages ../servers/monitoring/zabbix/agent.nix {}).${version}; + proxy-mysql = (callPackages ../servers/monitoring/zabbix/proxy.nix { mysqlSupport = true; }).${version}; + proxy-pgsql = (callPackages ../servers/monitoring/zabbix/proxy.nix { postgresqlSupport = true; }).${version}; + proxy-sqlite = (callPackages ../servers/monitoring/zabbix/proxy.nix { sqliteSupport = true; }).${version}; + server-mysql = (callPackages ../servers/monitoring/zabbix/server.nix { mysqlSupport = true; }).${version}; + server-pgsql = (callPackages ../servers/monitoring/zabbix/server.nix { postgresqlSupport = true; }).${version}; + web = (callPackages ../servers/monitoring/zabbix/web.nix {}).${version}; + + # backwards compatibility + server = server-pgsql; + }; + + zabbix42 = zabbixFor "v42"; + zabbix40 = zabbixFor "v40"; + zabbix30 = zabbixFor "v30"; + + zabbix = zabbix42; + + zipkin = callPackage ../servers/monitoring/zipkin { }; + + ### OS-SPECIFIC + + afuse = callPackage ../os-specific/linux/afuse { }; + + autofs5 = callPackage ../os-specific/linux/autofs { }; + + _915resolution = callPackage ../os-specific/linux/915resolution { }; + + nfs-utils = callPackage ../os-specific/linux/nfs-utils { }; + + acpi = callPackage ../os-specific/linux/acpi { }; + + acpid = callPackage ../os-specific/linux/acpid { }; + + acpitool = callPackage ../os-specific/linux/acpitool { }; + + alfred = callPackage ../os-specific/linux/batman-adv/alfred.nix { }; + + alienfx = callPackage ../os-specific/linux/alienfx { }; + + alsa-firmware = callPackage ../os-specific/linux/alsa-firmware { }; + + alsaLib = callPackage ../os-specific/linux/alsa-lib { }; + + alsaPlugins = callPackage ../os-specific/linux/alsa-plugins { }; + + alsaPluginWrapper = callPackage ../os-specific/linux/alsa-plugins/wrapper.nix { }; + + alsaUtils = callPackage ../os-specific/linux/alsa-utils { }; + alsaOss = callPackage ../os-specific/linux/alsa-oss { }; + alsaTools = callPackage ../os-specific/linux/alsa-tools { }; + + inherit (callPackage ../misc/arm-trusted-firmware {}) + buildArmTrustedFirmware + armTrustedFirmwareAllwinner + armTrustedFirmwareQemu + armTrustedFirmwareRK3328 + armTrustedFirmwareRK3399 + ; + + microcodeAmd = callPackage ../os-specific/linux/microcode/amd.nix { }; + + microcodeIntel = callPackage ../os-specific/linux/microcode/intel.nix { }; + + iucode-tool = callPackage ../os-specific/linux/microcode/iucode-tool.nix { }; + + inherit (callPackages ../os-specific/linux/apparmor { python = python3; }) + libapparmor apparmor-utils apparmor-bin-utils apparmor-parser apparmor-pam + apparmor-profiles apparmor-kernel-patches; + + atop = callPackage ../os-specific/linux/atop { }; + + audit = callPackage ../os-specific/linux/audit { }; + + b43Firmware_5_1_138 = callPackage ../os-specific/linux/firmware/b43-firmware/5.1.138.nix { }; + + b43Firmware_6_30_163_46 = callPackage ../os-specific/linux/firmware/b43-firmware/6.30.163.46.nix { }; + + b43FirmwareCutter = callPackage ../os-specific/linux/firmware/b43-firmware-cutter { }; + + bt-fw-converter = callPackage ../os-specific/linux/firmware/bt-fw-converter { }; + + broadcom-bt-firmware = callPackage ../os-specific/linux/firmware/broadcom-bt-firmware { }; + + batctl = callPackage ../os-specific/linux/batman-adv/batctl.nix { }; + + blktrace = callPackage ../os-specific/linux/blktrace { }; + + bluez5 = callPackage ../os-specific/linux/bluez { }; + + pulseaudio-modules-bt = callPackage ../applications/audio/pulseaudio-modules-bt { + # pulseaudio-modules-bt is most likely to be used with pulseaudioFull + pulseaudio = pulseaudioFull; + }; + + bluez = bluez5; + + bluezFull = bluez.override { + enableWiimote = true; + enableMidi = true; + enableSixaxis = true; + }; + + inherit (python3Packages) bedup; + + bolt = callPackage ../os-specific/linux/bolt { }; + + bridge-utils = callPackage ../os-specific/linux/bridge-utils { }; + + busybox = callPackage ../os-specific/linux/busybox { }; + busybox-sandbox-shell = callPackage ../os-specific/linux/busybox/sandbox-shell.nix { }; + + cachefilesd = callPackage ../os-specific/linux/cachefilesd { }; + + cgmanager = callPackage ../os-specific/linux/cgmanager { }; + + checkpolicy = callPackage ../os-specific/linux/checkpolicy { }; + + checksec = callPackage ../os-specific/linux/checksec { }; + + cifs-utils = callPackage ../os-specific/linux/cifs-utils { }; + + cockroachdb = callPackage ../servers/sql/cockroachdb { }; + + conky = callPackage ../os-specific/linux/conky ({ + lua = lua5_3_compat; + inherit (linuxPackages.nvidia_x11.settings) libXNVCtrl; + } // config.conky or {}); + + conntrack-tools = callPackage ../os-specific/linux/conntrack-tools { }; + + coredns = callPackage ../servers/dns/coredns { }; + + cpufrequtils = callPackage ../os-specific/linux/cpufrequtils { }; + + cpuset = callPackage ../os-specific/linux/cpuset { }; + + criu = callPackage ../os-specific/linux/criu { }; + + cryptsetup = callPackage ../os-specific/linux/cryptsetup { }; + + cramfsswap = callPackage ../os-specific/linux/cramfsswap { }; + + crda = callPackage ../os-specific/linux/crda { }; + + # Darwin package set + # + # Even though this is a set of packages not single package, use `callPackage` + # not `callPackages` so the per-package callPackages don't have their + # `.override` clobbered. C.F. `llvmPackages` which does the same. + darwin = callPackage ./darwin-packages.nix { }; + + disk_indicator = callPackage ../os-specific/linux/disk-indicator { }; + + displaylink = callPackage ../os-specific/linux/displaylink { + inherit (linuxPackages) evdi; + }; + + dmidecode = callPackage ../os-specific/linux/dmidecode { }; + + dmtcp = callPackage ../os-specific/linux/dmtcp { }; + + directvnc = callPackage ../os-specific/linux/directvnc { }; + + dmraid = callPackage ../os-specific/linux/dmraid { + lvm2 = lvm2.override {enable_dmeventd = true;}; + }; + + drbd = callPackage ../os-specific/linux/drbd { }; + + dropwatch = callPackage ../os-specific/linux/dropwatch { }; + + dstat = callPackage ../os-specific/linux/dstat { }; + + # unstable until the first 1.x release + fscrypt-experimental = callPackage ../os-specific/linux/fscrypt { + buildGoPackage = buildGo110Package; + }; + fscryptctl-experimental = callPackage ../os-specific/linux/fscryptctl { }; + + fwupd = callPackage ../os-specific/linux/firmware/fwupd { }; + + fwupdate = callPackage ../os-specific/linux/firmware/fwupdate { }; + + fwts = callPackage ../os-specific/linux/fwts { }; + + libossp_uuid = callPackage ../development/libraries/libossp-uuid { }; + + libuuid = if stdenv.isLinux + then utillinuxMinimal + else null; + + light = callPackage ../os-specific/linux/light { }; + + lightum = callPackage ../os-specific/linux/lightum { }; + + ebtables = callPackage ../os-specific/linux/ebtables { }; + + extrace = callPackage ../os-specific/linux/extrace { }; + + facetimehd-firmware = callPackage ../os-specific/linux/firmware/facetimehd-firmware { }; + + fatrace = callPackage ../os-specific/linux/fatrace { }; + + ffado = callPackage ../os-specific/linux/ffado { }; + libffado = ffado; + + fbterm = callPackage ../os-specific/linux/fbterm { }; + + firejail = callPackage ../os-specific/linux/firejail {}; + + fnotifystat = callPackage ../os-specific/linux/fnotifystat { }; + + forkstat = callPackage ../os-specific/linux/forkstat { }; + + freefall = callPackage ../os-specific/linux/freefall { + inherit (linuxPackages) kernel; + }; + + fusePackages = dontRecurseIntoAttrs (callPackage ../os-specific/linux/fuse { + utillinux = utillinuxMinimal; + }); + fuse = lowPrio fusePackages.fuse_2; + fuse3 = fusePackages.fuse_3; + fuse-common = hiPrio fusePackages.fuse_3.common; + + fxload = callPackage ../os-specific/linux/fxload { }; + + gfxtablet = callPackage ../os-specific/linux/gfxtablet {}; + + gmailieer = callPackage ../applications/networking/gmailieer {}; + + gpm = callPackage ../servers/gpm { + ncurses = null; # Keep curses disabled for lack of value + }; + + gpm-ncurses = gpm.override { inherit ncurses; }; + + gpu-switch = callPackage ../os-specific/linux/gpu-switch { }; + + gradm = callPackage ../os-specific/linux/gradm { }; + + hd-idle = callPackage ../os-specific/linux/hd-idle { }; + + hdparm = callPackage ../os-specific/linux/hdparm { }; + + hibernate = callPackage ../os-specific/linux/hibernate { }; + + hostapd = callPackage ../os-specific/linux/hostapd { }; + + htop = callPackage ../tools/system/htop { + inherit (darwin) IOKit; + }; + + nmon = callPackage ../os-specific/linux/nmon { }; + + hwdata = callPackage ../os-specific/linux/hwdata { }; + + i7z = qt5.callPackage ../os-specific/linux/i7z { }; + + pcm = callPackage ../os-specific/linux/pcm { }; + + ima-evm-utils = callPackage ../os-specific/linux/ima-evm-utils { + openssl = openssl_1_0_2; + }; + + intel2200BGFirmware = callPackage ../os-specific/linux/firmware/intel2200BGFirmware { }; + + intel-ocl = callPackage ../os-specific/linux/intel-ocl { }; + + iomelt = callPackage ../os-specific/linux/iomelt { }; + + iotop = callPackage ../os-specific/linux/iotop { }; + + iproute = callPackage ../os-specific/linux/iproute { }; + + iproute_mptcp = callPackage ../os-specific/linux/iproute/mptcp.nix { }; + + iputils = callPackage ../os-specific/linux/iputils { }; + + iptables = callPackage ../os-specific/linux/iptables { }; + + iptstate = callPackage ../os-specific/linux/iptstate { } ; + + ipset = callPackage ../os-specific/linux/ipset { }; + + irqbalance = callPackage ../os-specific/linux/irqbalance { }; + + iw = callPackage ../os-specific/linux/iw { }; + + iwd = callPackage ../os-specific/linux/iwd { }; + + jfbview = callPackage ../os-specific/linux/jfbview { }; + jfbpdf = jfbview.override { + imageSupport = false; + }; + + jool-cli = callPackage ../os-specific/linux/jool/cli.nix { }; + + jujuutils = callPackage ../os-specific/linux/jujuutils { }; + + kbd = callPackage ../os-specific/linux/kbd { }; + + kbdKeymaps = callPackage ../os-specific/linux/kbd/keymaps.nix { }; + + kbdlight = callPackage ../os-specific/linux/kbdlight { }; + + kmscon = callPackage ../os-specific/linux/kmscon { }; + + kmscube = callPackage ../os-specific/linux/kmscube { }; + + kmsxx = callPackage ../development/libraries/kmsxx { + stdenv = gcc6Stdenv; + }; + + latencytop = callPackage ../os-specific/linux/latencytop { }; + + ldm = callPackage ../os-specific/linux/ldm { }; + + libaio = callPackage ../os-specific/linux/libaio { }; + + libargon2 = callPackage ../development/libraries/libargon2 { }; + + libatasmart = callPackage ../os-specific/linux/libatasmart { }; + + libcgroup = callPackage ../os-specific/linux/libcgroup { }; + + libnl = callPackage ../os-specific/linux/libnl { }; + + linuxConsoleTools = callPackage ../os-specific/linux/consoletools { }; + + openelec-dvb-firmware = callPackage ../os-specific/linux/firmware/openelec-dvb-firmware { }; + + openiscsi = callPackage ../os-specific/linux/open-iscsi { }; + + openisns = callPackage ../os-specific/linux/open-isns { }; + + osxfuse = callPackage ../os-specific/darwin/osxfuse { }; + + powerstat = callPackage ../os-specific/linux/powerstat { }; + + smemstat = callPackage ../os-specific/linux/smemstat { }; + + tgt = callPackage ../tools/networking/tgt { }; + + # -- Linux kernel expressions ------------------------------------------------ + + lkl = callPackage ../applications/virtualization/lkl { }; + + inherit (callPackages ../os-specific/linux/kernel-headers { }) + linuxHeaders; + + kernelPatches = callPackage ../os-specific/linux/kernel/patches.nix { }; + + klibc = callPackage ../os-specific/linux/klibc { }; + + klibcShrunk = lowPrio (callPackage ../os-specific/linux/klibc/shrunk.nix { }); + + linux_mptcp = linux_mptcp_95; + + linux_mptcp_94 = callPackage ../os-specific/linux/kernel/linux-mptcp-94.nix { + kernelPatches = + [ kernelPatches.bridge_stp_helper + kernelPatches.cpu-cgroup-v2."4.11" + kernelPatches.modinst_arg_list_too_long + ] + ++ lib.optionals ((stdenv.hostPlatform.platform.kernelArch or null) == "mips") + [ kernelPatches.mips_fpureg_emu + kernelPatches.mips_fpu_sigill + kernelPatches.mips_ext3_n32 + ]; + }; + + linux_mptcp_95 = callPackage ../os-specific/linux/kernel/linux-mptcp-95.nix { + kernelPatches = linux_4_19.kernelPatches; + }; + + linux_rpi = callPackage ../os-specific/linux/kernel/linux-rpi.nix { + kernelPatches = with kernelPatches; [ + bridge_stp_helper + ]; + }; + + linux_4_4 = callPackage ../os-specific/linux/kernel/linux-4.4.nix { + kernelPatches = + [ kernelPatches.bridge_stp_helper + kernelPatches.cpu-cgroup-v2."4.4" + kernelPatches.modinst_arg_list_too_long + # https://github.com/NixOS/nixpkgs/issues/42755 + # Remove these xen-netfront patches once they're included in + # upstream! Fixes https://github.com/NixOS/nixpkgs/issues/42755 + kernelPatches.xen-netfront_fix_mismatched_rtnl_unlock + kernelPatches.xen-netfront_update_features_after_registering_netdev + ]; + }; + + linux_4_9 = callPackage ../os-specific/linux/kernel/linux-4.9.nix { + kernelPatches = + [ kernelPatches.bridge_stp_helper + kernelPatches.cpu-cgroup-v2."4.9" + kernelPatches.modinst_arg_list_too_long + ]; + }; + + linux_4_14 = callPackage ../os-specific/linux/kernel/linux-4.14.nix { + kernelPatches = + [ kernelPatches.bridge_stp_helper + # See pkgs/os-specific/linux/kernel/cpu-cgroup-v2-patches/README.md + # when adding a new linux version + kernelPatches.cpu-cgroup-v2."4.11" + kernelPatches.modinst_arg_list_too_long + kernelPatches.export_kernel_fpu_functions + ]; + }; + + linux_4_19 = callPackage ../os-specific/linux/kernel/linux-4.19.nix { + kernelPatches = + [ kernelPatches.bridge_stp_helper + kernelPatches.modinst_arg_list_too_long + kernelPatches.export_kernel_fpu_functions + ]; + }; + + linux_5_1 = callPackage ../os-specific/linux/kernel/linux-5.1.nix { + kernelPatches = + [ kernelPatches.bridge_stp_helper + kernelPatches.modinst_arg_list_too_long + kernelPatches.export_kernel_fpu_functions + ]; + }; + + linux_5_2 = callPackage ../os-specific/linux/kernel/linux-5.2.nix { + kernelPatches = + [ kernelPatches.bridge_stp_helper + kernelPatches.modinst_arg_list_too_long + kernelPatches.export_kernel_fpu_functions + ]; + }; + + linux_testing = callPackage ../os-specific/linux/kernel/linux-testing.nix { + kernelPatches = [ + kernelPatches.bridge_stp_helper + kernelPatches.modinst_arg_list_too_long + kernelPatches.export_kernel_fpu_functions + ]; + }; + + linux_testing_bcachefs = callPackage ../os-specific/linux/kernel/linux-testing-bcachefs.nix { + kernelPatches = + [ kernelPatches.bridge_stp_helper + kernelPatches.modinst_arg_list_too_long + ]; + }; + + linux_hardkernel_4_14 = callPackage ../os-specific/linux/kernel/linux-hardkernel-4.14.nix { + kernelPatches = [ + kernelPatches.bridge_stp_helper + kernelPatches.modinst_arg_list_too_long + ]; + }; + + /* Linux kernel modules are inherently tied to a specific kernel. So + rather than provide specific instances of those packages for a + specific kernel, we have a function that builds those packages + for a specific kernel. This function can then be called for + whatever kernel you're using. */ + + linuxPackagesFor = kernel: lib.makeExtensible (self: with self; { + callPackage = newScope self; + + inherit kernel; + inherit (kernel) stdenv; # in particular, use the same compiler by default + + # Obsolete aliases (these packages do not depend on the kernel). + inherit (pkgs) odp-dpdk pktgen; # added 2018-05 + + acpi_call = callPackage ../os-specific/linux/acpi-call {}; + + amdgpu-pro = callPackage ../os-specific/linux/amdgpu-pro { }; + + anbox = callPackage ../os-specific/linux/anbox/kmod.nix { }; + + batman_adv = callPackage ../os-specific/linux/batman-adv {}; + + bcc = callPackage ../os-specific/linux/bcc { + python = python3; + }; + + bpftrace = callPackage ../os-specific/linux/bpftrace { }; + + bbswitch = callPackage ../os-specific/linux/bbswitch {}; + + beegfs-module = callPackage ../os-specific/linux/beegfs/kernel-module.nix { }; + + ati_drivers_x11 = callPackage ../os-specific/linux/ati-drivers { }; + + blcr = if stdenv.lib.versionOlder "3.18" kernel.version then callPackage ../os-specific/linux/blcr { } else null; + + chipsec = callPackage ../tools/security/chipsec { + inherit kernel; + withDriver = true; + }; + + cryptodev = callPackage ../os-specific/linux/cryptodev { }; + + cpupower = callPackage ../os-specific/linux/cpupower { }; + + deepin-anything = callPackage ../os-specific/linux/deepin-anything { }; + + dpdk = callPackage ../os-specific/linux/dpdk { }; + + exfat-nofuse = callPackage ../os-specific/linux/exfat { }; + + evdi = callPackage ../os-specific/linux/evdi { }; + + hyperv-daemons = callPackage ../os-specific/linux/hyperv-daemons { }; + + e1000e = if stdenv.lib.versionOlder kernel.version "4.10" then callPackage ../os-specific/linux/e1000e {} else null; + + ixgbevf = callPackage ../os-specific/linux/ixgbevf {}; + + it87 = callPackage ../os-specific/linux/it87 {}; + + ena = callPackage ../os-specific/linux/ena {}; + + v4l2loopback = callPackage ../os-specific/linux/v4l2loopback { }; + + lttng-modules = callPackage ../os-specific/linux/lttng-modules { }; + + broadcom_sta = callPackage ../os-specific/linux/broadcom-sta { }; + + tbs = callPackage ../os-specific/linux/tbs { }; + + nvidiabl = callPackage ../os-specific/linux/nvidiabl { }; + + nvidiaPackages = dontRecurseIntoAttrs (callPackage ../os-specific/linux/nvidia-x11 { }); + + nvidia_x11_legacy304 = nvidiaPackages.legacy_304; + nvidia_x11_legacy340 = nvidiaPackages.legacy_340; + nvidia_x11_legacy390 = nvidiaPackages.legacy_390; + nvidia_x11_beta = nvidiaPackages.beta; + nvidia_x11 = nvidiaPackages.stable; + + ply = callPackage ../os-specific/linux/ply { }; + + r8168 = callPackage ../os-specific/linux/r8168 { }; + + rtl8192eu = callPackage ../os-specific/linux/rtl8192eu { }; + + rtl8723bs = callPackage ../os-specific/linux/rtl8723bs { }; + + rtl8812au = callPackage ../os-specific/linux/rtl8812au { }; + + rtl8814au = callPackage ../os-specific/linux/rtl8814au { }; + + rtl8821au = callPackage ../os-specific/linux/rtl8821au { }; + + rtl8821ce = callPackage ../os-specific/linux/rtl8821ce { }; + + rtlwifi_new = callPackage ../os-specific/linux/rtlwifi_new { }; + + openafs = callPackage ../servers/openafs/1.6/module.nix { }; + openafs_1_8 = callPackage ../servers/openafs/1.8/module.nix { }; + + facetimehd = callPackage ../os-specific/linux/facetimehd { }; + + jool = callPackage ../os-specific/linux/jool { }; + + mba6x_bl = callPackage ../os-specific/linux/mba6x_bl { }; + + mwprocapture = callPackage ../os-specific/linux/mwprocapture { }; + + mxu11x0 = callPackage ../os-specific/linux/mxu11x0 { }; + + /* compiles but has to be integrated into the kernel somehow + Let's have it uncommented and finish it.. + */ + ndiswrapper = callPackage ../os-specific/linux/ndiswrapper { }; + + netatop = callPackage ../os-specific/linux/netatop { }; + + perf = callPackage ../os-specific/linux/kernel/perf.nix { }; + + phc-intel = callPackage ../os-specific/linux/phc-intel { }; + + # Disable for kernels 4.15 and above due to compatibility issues + prl-tools = if stdenv.lib.versionOlder kernel.version "4.15" then callPackage ../os-specific/linux/prl-tools { } else null; + + sch_cake = callPackage ../os-specific/linux/sch_cake { }; + + sysdig = callPackage ../os-specific/linux/sysdig {}; + + systemtap = callPackage ../development/tools/profiling/systemtap { }; + + tmon = callPackage ../os-specific/linux/tmon { }; + + tp_smapi = callPackage ../os-specific/linux/tp_smapi { }; + + usbip = callPackage ../os-specific/linux/usbip { }; + + v86d = callPackage ../os-specific/linux/v86d { }; + + vhba = callPackage ../misc/emulators/cdemu/vhba.nix { }; + + virtualbox = callPackage ../os-specific/linux/virtualbox { + virtualbox = pkgs.virtualboxHardened; + }; + + virtualboxGuestAdditions = callPackage ../applications/virtualization/virtualbox/guest-additions { + virtualbox = pkgs.virtualboxHardened; + }; + + wireguard = callPackage ../os-specific/linux/wireguard { }; + + x86_energy_perf_policy = callPackage ../os-specific/linux/x86_energy_perf_policy { }; + + inherit (callPackage ../os-specific/linux/zfs { + configFile = "kernel"; + inherit kernel; + }) zfsStable zfsUnstable; + + zfs = zfsStable; + + can-isotp = callPackage ../os-specific/linux/can-isotp { }; + }); + + # The current default kernel / kernel modules. + linuxPackages = linuxPackages_4_19; + linux = linuxPackages.kernel; + + # Update this when adding the newest kernel major version! + linuxPackages_latest = linuxPackages_5_2; + linux_latest = linuxPackages_latest.kernel; + + # Build the kernel modules for the some of the kernels. + linuxPackages_mptcp = linuxPackagesFor pkgs.linux_mptcp; + linuxPackages_rpi = linuxPackagesFor pkgs.linux_rpi; + linuxPackages_4_4 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_4_4); + linuxPackages_4_9 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_4_9); + linuxPackages_4_14 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_4_14); + linuxPackages_4_19 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_4_19); + linuxPackages_5_1 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_5_1); + linuxPackages_5_2 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_5_2); + + # When adding to this list: + # - Update linuxPackages_latest to the latest version + # - Update the rev in ../os-specific/linux/kernel/linux-libre.nix to the latest one. + + # Intentionally lacks recurseIntoAttrs, as -rc kernels will quite likely break out-of-tree modules and cause failed Hydra builds. + linuxPackages_testing = linuxPackagesFor pkgs.linux_testing; + + linuxPackages_custom = { version, src, configfile, allowImportFromDerivation ? true }: + recurseIntoAttrs (linuxPackagesFor (pkgs.linuxManualConfig { + inherit version src configfile stdenv allowImportFromDerivation; + })); + + # This serves as a test for linuxPackages_custom + linuxPackages_custom_tinyconfig_kernel = let + base = pkgs.linuxPackages.kernel; + tinyLinuxPackages = pkgs.linuxPackages_custom { + inherit (base) version src; + allowImportFromDerivation = false; + configfile = pkgs.linuxConfig { + makeTarget = "tinyconfig"; + src = base.src; + }; + }; + in tinyLinuxPackages.kernel; + + # Build a kernel with bcachefs module + linuxPackages_testing_bcachefs = recurseIntoAttrs (linuxPackagesFor pkgs.linux_testing_bcachefs); + + # Build a kernel for Xen dom0 + linuxPackages_xen_dom0 = recurseIntoAttrs (linuxPackagesFor (pkgs.linux.override { features.xen_dom0=true; })); + + linuxPackages_latest_xen_dom0 = recurseIntoAttrs (linuxPackagesFor (pkgs.linux_latest.override { features.xen_dom0=true; })); + + # Hardened linux + hardenedLinuxPackagesFor = kernel: linuxPackagesFor (kernel.override { + features.ia32Emulation = false; + structuredExtraConfig = import ../os-specific/linux/kernel/hardened-config.nix { + inherit stdenv; + inherit (kernel) version; + }; + kernelPatches = kernel.kernelPatches ++ [ kernelPatches.tag_hardened ]; + modDirVersionArg = kernel.modDirVersion + "-hardened"; + }); + + linuxPackages_hardened = recurseIntoAttrs (hardenedLinuxPackagesFor pkgs.linux); + linux_hardened = linuxPackages_hardened.kernel; + + linuxPackages_latest_hardened = recurseIntoAttrs (hardenedLinuxPackagesFor pkgs.linux_latest); + linux_latest_hardened = linuxPackages_latest_hardened.kernel; + + linuxPackages_testing_hardened = recurseIntoAttrs (hardenedLinuxPackagesFor pkgs.linux_testing); + linux_testing_hardened = linuxPackages_testing_hardened.kernel; + + linuxPackages_xen_dom0_hardened = recurseIntoAttrs (hardenedLinuxPackagesFor (pkgs.linux.override { features.xen_dom0=true; })); + + linuxPackages_latest_xen_dom0_hardened = recurseIntoAttrs (hardenedLinuxPackagesFor (pkgs.linux_latest.override { features.xen_dom0=true; })); + + # Hardkernel (Odroid) kernels. + linuxPackages_hardkernel_4_14 = recurseIntoAttrs (linuxPackagesFor pkgs.linux_hardkernel_4_14); + linuxPackages_hardkernel_latest = linuxPackages_hardkernel_4_14; + linux_hardkernel_latest = linuxPackages_hardkernel_latest.kernel; + + # GNU Linux-libre kernels + linuxPackages-libre = recurseIntoAttrs (linuxPackagesFor linux-libre); + linux-libre = callPackage ../os-specific/linux/kernel/linux-libre.nix {}; + linuxPackages_latest-libre = recurseIntoAttrs (linuxPackagesFor linux_latest-libre); + linux_latest-libre = linux-libre.override { linux = linux_latest; }; + + # A function to build a manually-configured kernel + linuxManualConfig = makeOverridable (callPackage ../os-specific/linux/kernel/manual-config.nix {}); + + # Derive one of the default .config files + linuxConfig = { src, makeTarget ? "defconfig", name ? "kernel.config" }: + stdenv.mkDerivation { + inherit name src; + buildPhase = '' + set -x + make ${makeTarget} + ''; + installPhase = '' + cp .config $out + ''; + }; + + buildLinux = attrs: callPackage ../os-specific/linux/kernel/generic.nix attrs; + + cryptodev = linuxPackages_4_9.cryptodev; + + dpdk = callPackage ../os-specific/linux/dpdk { + kernel = null; # dpdk modules are in linuxPackages.dpdk.kmod + }; + + keyutils = callPackage ../os-specific/linux/keyutils { }; + + libselinux = callPackage ../os-specific/linux/libselinux { }; + + libsemanage = callPackage ../os-specific/linux/libsemanage { }; + + libraw = callPackage ../development/libraries/libraw { }; + + libraw1394 = callPackage ../development/libraries/libraw1394 { }; + + librealsense = callPackage ../development/libraries/librealsense { }; + + libsass = callPackage ../development/libraries/libsass { }; + + libsexy = callPackage ../development/libraries/libsexy { }; + + libsepol = callPackage ../os-specific/linux/libsepol { }; + + libsmbios = callPackage ../os-specific/linux/libsmbios { }; + + lm_sensors = callPackage ../os-specific/linux/lm-sensors { }; + + lockdep = callPackage ../os-specific/linux/lockdep { }; + + lsiutil = callPackage ../os-specific/linux/lsiutil { }; + + kmod = callPackage ../os-specific/linux/kmod { }; + + kmod-blacklist-ubuntu = callPackage ../os-specific/linux/kmod-blacklist-ubuntu { }; + + kmod-debian-aliases = callPackage ../os-specific/linux/kmod-debian-aliases { }; + + libcap = callPackage ../os-specific/linux/libcap { }; + + libcap_ng = callPackage ../os-specific/linux/libcap-ng { + swig = null; # Currently not using the python2/3 bindings + python2 = null; # Currently not using the python2 bindings + python3 = null; # Currently not using the python3 bindings + }; + + libnotify = callPackage ../development/libraries/libnotify { }; + + libvolume_id = callPackage ../os-specific/linux/libvolume_id { }; + + lsscsi = callPackage ../os-specific/linux/lsscsi { }; + + lvm2 = callPackage ../os-specific/linux/lvm2 { }; + + mbpfan = callPackage ../os-specific/linux/mbpfan { }; + + mdadm = mdadm4; + mdadm4 = callPackage ../os-specific/linux/mdadm { }; + + mingetty = callPackage ../os-specific/linux/mingetty { }; + + miraclecast = callPackage ../os-specific/linux/miraclecast { }; + + mkinitcpio-nfs-utils = callPackage ../os-specific/linux/mkinitcpio-nfs-utils { }; + + mmc-utils = callPackage ../os-specific/linux/mmc-utils { }; + + aggregateModules = modules: + callPackage ../os-specific/linux/kmod/aggregator.nix { + inherit (buildPackages) kmod; + inherit modules; + }; + + multipart-parser-c = callPackage ../development/libraries/multipart-parser-c { }; + + multipath-tools = callPackage ../os-specific/linux/multipath-tools { }; + + musl = callPackage ../os-specific/linux/musl { }; + + nettools = if stdenv.isLinux then callPackage ../os-specific/linux/net-tools { } + else unixtools.nettools; + + nettools_mptcp = callPackage ../os-specific/linux/net-tools/mptcp.nix { }; + + nftables = callPackage ../os-specific/linux/nftables { }; + + noah = callPackage ../os-specific/darwin/noah { + inherit (darwin.apple_sdk.frameworks) Hypervisor; + }; + + numactl = callPackage ../os-specific/linux/numactl { }; + + numad = callPackage ../os-specific/linux/numad { }; + + nvme-cli = callPackage ../os-specific/linux/nvme-cli { }; + + open-vm-tools = callPackage ../applications/virtualization/open-vm-tools { }; + open-vm-tools-headless = open-vm-tools.override { withX = false; }; + + delve = callPackage ../development/tools/delve { }; + + dep = callPackage ../development/tools/dep { }; + + dep2nix = callPackage ../development/tools/dep2nix { }; + + easyjson = callPackage ../development/tools/easyjson { }; + + iferr = callPackage ../development/tools/iferr { }; + + go-bindata = callPackage ../development/tools/go-bindata { }; + + go-bindata-assetfs = callPackage ../development/tools/go-bindata-assetfs { }; + + go-protobuf = callPackage ../development/tools/go-protobuf { }; + + go-symbols = callPackage ../development/tools/go-symbols { }; + + go-outline = callPackage ../development/tools/go-outline { }; + + gocode = callPackage ../development/tools/gocode { }; + + gocode-gomod = callPackage ../development/tools/gocode-gomod { }; + + goconst = callPackage ../development/tools/goconst { }; + + goconvey = callPackage ../development/tools/goconvey { }; + + gotags = callPackage ../development/tools/gotags { }; + + golint = callPackage ../development/tools/golint { }; + + golangci-lint = callPackage ../development/tools/golangci-lint { }; + + gocyclo = callPackage ../development/tools/gocyclo { }; + + godef = callPackage ../development/tools/godef { }; + + gopkgs = callPackage ../development/tools/gopkgs { }; + + gosec = callPackage ../development/tools/gosec { }; + + govers = callPackage ../development/tools/govers { }; + + govendor = callPackage ../development/tools/govendor { }; + + go-tools = callPackage ../development/tools/go-tools { }; + + gotools = callPackage ../development/tools/gotools { }; + + gotop = callPackage ../tools/system/gotop { }; + + gomodifytags = callPackage ../development/tools/gomodifytags { }; + + go-langserver = callPackage ../development/tools/go-langserver { }; + + gotests = callPackage ../development/tools/gotests { }; + + impl = callPackage ../development/tools/impl { }; + + quicktemplate = callPackage ../development/tools/quicktemplate { }; + + gogoclient = callPackage ../os-specific/linux/gogoclient { + openssl = openssl_1_0_2; + }; + + linux-pam = callPackage ../os-specific/linux/pam { }; + + nss_ldap = callPackage ../os-specific/linux/nss_ldap { }; + + odp-dpdk = callPackage ../os-specific/linux/odp-dpdk { }; + + odroid-xu3-bootloader = callPackage ../tools/misc/odroid-xu3-bootloader { }; + + ofp = callPackage ../os-specific/linux/ofp { }; + + ofono = callPackage ../tools/networking/ofono { }; + + openpam = callPackage ../development/libraries/openpam { }; + + openbsm = callPackage ../development/libraries/openbsm { }; + + pagemon = callPackage ../os-specific/linux/pagemon { }; + + pam = if stdenv.isLinux then linux-pam else openpam; + + # pam_bioapi ( see http://www.thinkwiki.org/wiki/How_to_enable_the_fingerprint_reader ) + + pam_ccreds = callPackage ../os-specific/linux/pam_ccreds { }; + + pam_krb5 = callPackage ../os-specific/linux/pam_krb5 { }; + + pam_ldap = callPackage ../os-specific/linux/pam_ldap { }; + + pam_mount = callPackage ../os-specific/linux/pam_mount { }; + + pam_pgsql = callPackage ../os-specific/linux/pam_pgsql { }; + + pam_ssh_agent_auth = callPackage ../os-specific/linux/pam_ssh_agent_auth { + openssl = openssl_1_0_2; + }; + + pam_u2f = callPackage ../os-specific/linux/pam_u2f { }; + + pam_usb = callPackage ../os-specific/linux/pam_usb { }; + + paxctl = callPackage ../os-specific/linux/paxctl { }; + + paxtest = callPackage ../os-specific/linux/paxtest { }; + + pax-utils = callPackage ../os-specific/linux/pax-utils { }; + + pcmciaUtils = callPackage ../os-specific/linux/pcmciautils { }; + + pcstat = callPackage ../tools/system/pcstat { }; + + perf-tools = callPackage ../os-specific/linux/perf-tools { }; + + pipes = callPackage ../misc/screensavers/pipes { }; + + pipework = callPackage ../os-specific/linux/pipework { }; + + pktgen = callPackage ../os-specific/linux/pktgen { }; + + plymouth = callPackage ../os-specific/linux/plymouth { }; + + pmount = callPackage ../os-specific/linux/pmount { }; + + pmutils = callPackage ../os-specific/linux/pm-utils { }; + + policycoreutils = callPackage ../os-specific/linux/policycoreutils { }; + + semodule-utils = callPackage ../os-specific/linux/semodule-utils { }; + + powerdns = callPackage ../servers/dns/powerdns { libressl = libressl_2_8; }; + + dnsdist = callPackage ../servers/dns/dnsdist { }; + + pdns-recursor = callPackage ../servers/dns/pdns-recursor { }; + + powertop = callPackage ../os-specific/linux/powertop { }; + + pps-tools = callPackage ../os-specific/linux/pps-tools { }; + + prayer = callPackage ../servers/prayer { }; + + procps = if stdenv.isLinux then callPackage ../os-specific/linux/procps-ng { } + else unixtools.procps; + + procdump = callPackage ../os-specific/linux/procdump { }; + + prototool = callPackage ../development/tools/prototool { }; + + qemu_kvm = lowPrio (qemu.override { hostCpuOnly = true; }); + + # See `xenPackages` source for explanations. + # Building with `xen` instead of `xen-slim` is possible, but makes no sense. + qemu_xen = lowPrio (qemu.override { hostCpuOnly = true; xenSupport = true; xen = xen-slim; }); + qemu_xen-light = lowPrio (qemu.override { hostCpuOnly = true; xenSupport = true; xen = xen-light; }); + qemu_xen_4_8 = lowPrio (qemu.override { hostCpuOnly = true; xenSupport = true; xen = xen_4_8-slim; }); + qemu_xen_4_8-light = lowPrio (qemu.override { hostCpuOnly = true; xenSupport = true; xen = xen_4_8-light; }); + qemu_xen_4_10 = lowPrio (qemu.override { hostCpuOnly = true; xenSupport = true; xen = xen_4_10-slim; }); + qemu_xen_4_10-light = lowPrio (qemu.override { hostCpuOnly = true; xenSupport = true; xen = xen_4_10-light; }); + + qemu_test = lowPrio (qemu.override { hostCpuOnly = true; nixosTestRunner = true; }); + + firmwareLinuxNonfree = callPackage ../os-specific/linux/firmware/firmware-linux-nonfree { }; + + radeontools = callPackage ../os-specific/linux/radeontools { }; + + radeontop = callPackage ../os-specific/linux/radeontop { }; + + raspberrypifw = callPackage ../os-specific/linux/firmware/raspberrypi {}; + raspberrypiWirelessFirmware = callPackage ../os-specific/linux/firmware/raspberrypi-wireless { }; + + raspberrypi-tools = callPackage ../os-specific/linux/firmware/raspberrypi/tools.nix {}; + + regionset = callPackage ../os-specific/linux/regionset { }; + + rfkill = callPackage ../os-specific/linux/rfkill { }; + + rfkill_udev = callPackage ../os-specific/linux/rfkill/udev.nix { }; + + riscv-pk = callPackage ../misc/riscv-pk { }; + + riscv-pk-with-kernel = riscv-pk.override { + payload = "${linux_riscv}/vmlinux"; + }; + + roccat-tools = callPackage ../os-specific/linux/roccat-tools { }; + + rtkit = callPackage ../os-specific/linux/rtkit { }; + + rt5677-firmware = callPackage ../os-specific/linux/firmware/rt5677 { }; + + rtl8192su-firmware = callPackage ../os-specific/linux/firmware/rtl8192su-firmware { }; + + rtl8723bs-firmware = callPackage ../os-specific/linux/firmware/rtl8723bs-firmware { }; + + rtlwifi_new-firmware = callPackage ../os-specific/linux/firmware/rtlwifi_new-firmware { }; + + s3ql = callPackage ../tools/backup/s3ql { }; + + sass = callPackage ../development/tools/sass { }; + + sassc = callPackage ../development/tools/sassc { }; + + scanmem = callPackage ../tools/misc/scanmem { }; + + schedtool = callPackage ../os-specific/linux/schedtool { }; + + sdparm = callPackage ../os-specific/linux/sdparm { }; + + sepolgen = callPackage ../os-specific/linux/sepolgen { }; + + setools = callPackage ../os-specific/linux/setools { }; + + seturgent = callPackage ../os-specific/linux/seturgent { }; + + shadow = callPackage ../os-specific/linux/shadow { }; + + sinit = callPackage ../os-specific/linux/sinit { + rcinit = "/etc/rc.d/rc.init"; + rcshutdown = "/etc/rc.d/rc.shutdown"; + }; + + skopeo = callPackage ../development/tools/skopeo { }; + + smem = callPackage ../os-specific/linux/smem { }; + + smimesign = callPackage ../os-specific/darwin/smimesign { }; + + speedometer = callPackage ../os-specific/linux/speedometer { }; + + statik = callPackage ../development/tools/statik { }; + + statifier = callPackage ../os-specific/linux/statifier { }; + + sysdig = callPackage ../os-specific/linux/sysdig { + kernel = null; + }; # pkgs.sysdig is a client, for a driver look at linuxPackagesFor + + sysfsutils = callPackage ../os-specific/linux/sysfsutils { }; + + sysprof = callPackage ../development/tools/profiling/sysprof { }; + + sysklogd = callPackage ../os-specific/linux/sysklogd { }; + + syslinux = callPackage ../os-specific/linux/syslinux { }; + + sysstat = callPackage ../os-specific/linux/sysstat { }; + + systemd = callPackage ../os-specific/linux/systemd { + utillinux = utillinuxMinimal; # break the cyclic dependency + }; + udev = systemd; # TODO: move to aliases.nix + + # standalone cryptsetup generator for systemd + systemd-cryptsetup-generator = callPackage ../os-specific/linux/systemd/cryptsetup-generator.nix { }; + + # In nixos, you can set systemd.package = pkgs.systemd_with_lvm2 to get + # LVM2 working in systemd. + systemd_with_lvm2 = pkgs.appendToName "with-lvm2" (pkgs.lib.overrideDerivation pkgs.systemd (p: { + postInstall = p.postInstall + '' + cp "${pkgs.lvm2}/lib/systemd/system-generators/"* $out/lib/systemd/system-generators + ''; + })); + + systemd-wait = callPackage ../os-specific/linux/systemd-wait { }; + + sysvinit = callPackage ../os-specific/linux/sysvinit { }; + + sysvtools = sysvinit.override { + withoutInitTools = true; + }; + + # FIXME: `tcp-wrapper' is actually not OS-specific. + tcp_wrappers = callPackage ../os-specific/linux/tcp-wrappers { }; + + tiptop = callPackage ../os-specific/linux/tiptop { }; + + tpacpi-bat = callPackage ../os-specific/linux/tpacpi-bat { }; + + trinity = callPackage ../os-specific/linux/trinity { }; + + tunctl = callPackage ../os-specific/linux/tunctl { }; + + twa = callPackage ../tools/networking/twa { }; + + # Upstream U-Boots: + inherit (callPackage ../misc/uboot {}) + buildUBoot + ubootTools + ubootA20OlinuxinoLime + ubootBananaPi + ubootBananaPim64 + ubootBeagleboneBlack + ubootClearfog + ubootGuruplug + ubootJetsonTK1 + ubootNovena + ubootOdroidXU3 + ubootOrangePiPc + ubootOrangePiZeroPlus2H5 + ubootPcduino3Nano + ubootPine64 + ubootPine64LTS + ubootPinebook + ubootQemuAarch64 + ubootQemuArm + ubootRaspberryPi + ubootRaspberryPi2 + ubootRaspberryPi3_32bit + ubootRaspberryPi3_64bit + ubootRaspberryPiZero + ubootSheevaplug + ubootSopine + ubootUtilite + ubootWandboard + ; + + # Non-upstream U-Boots: + ubootNanonote = callPackage ../misc/uboot/nanonote.nix { }; + + ubootRock64 = callPackage ../misc/uboot/rock64.nix { }; + + ubootRockPro64 = callPackage ../misc/uboot/rockpro64.nix { }; + + uclibc = callPackage ../os-specific/linux/uclibc { }; + + uclibcCross = callPackage ../os-specific/linux/uclibc { + stdenv = crossLibcStdenv; + }; + + eudev = callPackage ../os-specific/linux/eudev { utillinux = utillinuxMinimal; }; + + libudev0-shim = callPackage ../os-specific/linux/libudev0-shim { }; + + udisks1 = callPackage ../os-specific/linux/udisks/1-default.nix { }; + udisks2 = callPackage ../os-specific/linux/udisks/2-default.nix { }; + udisks = udisks2; + + udisks_glue = callPackage ../os-specific/linux/udisks-glue { }; + + untie = callPackage ../os-specific/linux/untie { }; + + upower = callPackage ../os-specific/linux/upower { }; + + usbguard = libsForQt5.callPackage ../os-specific/linux/usbguard { + libgcrypt = null; + }; + + usbguard-nox = usbguard.override { + withGui = false; + }; + + usbutils = callPackage ../os-specific/linux/usbutils { }; + + usermount = callPackage ../os-specific/linux/usermount { }; + + utillinux = if stdenv.isLinux then callPackage ../os-specific/linux/util-linux { } + else unixtools.utillinux; + + utillinuxCurses = utillinux; + + utillinuxMinimal = if stdenv.isLinux then appendToName "minimal" (utillinux.override { + minimal = true; + ncurses = null; + perl = null; + systemd = null; + }) else utillinux; + + v4l-utils = qt5.callPackage ../os-specific/linux/v4l-utils { }; + + vndr = callPackage ../development/tools/vndr { }; + + windows = callPackages ../os-specific/windows {}; + + wirelesstools = callPackage ../os-specific/linux/wireless-tools { }; + + wpa_supplicant = callPackage ../os-specific/linux/wpa_supplicant { }; + + wpa_supplicant_gui = libsForQt5.callPackage ../os-specific/linux/wpa_supplicant/gui.nix { }; + + xf86_input_mtrack = callPackage ../os-specific/linux/xf86-input-mtrack { }; + + xf86_input_multitouch = callPackage ../os-specific/linux/xf86-input-multitouch { }; + + xf86_input_wacom = callPackage ../os-specific/linux/xf86-input-wacom { }; + + xf86_video_nested = callPackage ../os-specific/linux/xf86-video-nested { }; + + xorg_sys_opengl = callPackage ../os-specific/linux/opengl/xorg-sys { }; + + zd1211fw = callPackage ../os-specific/linux/firmware/zd1211 { }; + + inherit (callPackage ../os-specific/linux/zfs { + configFile = "user"; + }) zfsStable zfsUnstable; + + zfs = zfsStable; + + ### DATA + + adapta-backgrounds = callPackage ../data/misc/adapta-backgrounds { }; + + adementary-theme = callPackage ../data/themes/adementary { }; + + agave = callPackage ../data/fonts/agave { }; + + aileron = callPackage ../data/fonts/aileron { }; + + amiri = callPackage ../data/fonts/amiri { }; + + andagii = callPackage ../data/fonts/andagii { }; + + andika = callPackage ../data/fonts/andika { }; + + android-udev-rules = callPackage ../os-specific/linux/android-udev-rules { }; + + ankacoder = callPackage ../data/fonts/ankacoder { }; + ankacoder-condensed = callPackage ../data/fonts/ankacoder/condensed.nix { }; + + anonymousPro = callPackage ../data/fonts/anonymous-pro { }; + + ant-theme = callPackage ../data/themes/ant-theme { }; + + arc-icon-theme = callPackage ../data/icons/arc-icon-theme { }; + + arkpandora_ttf = callPackage ../data/fonts/arkpandora { }; + + aurulent-sans = callPackage ../data/fonts/aurulent-sans { }; + + b612 = callPackage ../data/fonts/b612 { }; + + babelstone-han = callPackage ../data/fonts/babelstone-han { }; + + baekmuk-ttf = callPackage ../data/fonts/baekmuk-ttf { }; + + bakoma_ttf = callPackage ../data/fonts/bakoma-ttf { }; + + bgnet = callPackage ../data/documentation/bgnet { }; + + bibata-cursors = callPackage ../data/icons/bibata-cursors { }; + + brise = callPackage ../data/misc/brise { }; + + inherit (kdeFrameworks) breeze-icons; + + cacert = callPackage ../data/misc/cacert { }; + + caladea = callPackage ../data/fonts/caladea {}; + + cantarell-fonts = callPackage ../data/fonts/cantarell-fonts { }; + + capitaine-cursors = callPackage ../data/icons/capitaine-cursors { }; + + carlito = callPackage ../data/fonts/carlito {}; + + charis-sil = callPackage ../data/fonts/charis-sil { }; + + cherry = callPackage ../data/fonts/cherry { }; + + cnstrokeorder = callPackage ../data/fonts/cnstrokeorder {}; + + comfortaa = callPackage ../data/fonts/comfortaa {}; + + comic-neue = callPackage ../data/fonts/comic-neue { }; + + comic-relief = callPackage ../data/fonts/comic-relief {}; + + coreclr = callPackage ../development/compilers/coreclr { }; + + corefonts = callPackage ../data/fonts/corefonts { }; + + culmus = callPackage ../data/fonts/culmus { }; + + clearlyU = callPackage ../data/fonts/clearlyU { }; + + cm_unicode = callPackage ../data/fonts/cm-unicode {}; + + creep = callPackage ../data/fonts/creep { }; + + crimson = callPackage ../data/fonts/crimson {}; + + dejavu_fonts = lowPrio (callPackage ../data/fonts/dejavu-fonts {}); + + # solve collision for nix-env before https://github.com/NixOS/nix/pull/815 + dejavu_fontsEnv = buildEnv { + name = "${dejavu_fonts.name}"; + paths = [ dejavu_fonts.out ]; + }; + + dina-font = callPackage ../data/fonts/dina { }; + + dina-font-pcf = callPackage ../data/fonts/dina-pcf { }; + + dns-root-data = callPackage ../data/misc/dns-root-data { }; + + docbook5 = callPackage ../data/sgml+xml/schemas/docbook-5.0 { }; + + docbook_sgml_dtd_31 = callPackage ../data/sgml+xml/schemas/sgml-dtd/docbook/3.1.nix { }; + + docbook_sgml_dtd_41 = callPackage ../data/sgml+xml/schemas/sgml-dtd/docbook/4.1.nix { }; + + docbook_xml_dtd_412 = callPackage ../data/sgml+xml/schemas/xml-dtd/docbook/4.1.2.nix { }; + + docbook_xml_dtd_42 = callPackage ../data/sgml+xml/schemas/xml-dtd/docbook/4.2.nix { }; + + docbook_xml_dtd_43 = callPackage ../data/sgml+xml/schemas/xml-dtd/docbook/4.3.nix { }; + + docbook_xml_dtd_44 = callPackage ../data/sgml+xml/schemas/xml-dtd/docbook/4.4.nix { }; + + docbook_xml_dtd_45 = callPackage ../data/sgml+xml/schemas/xml-dtd/docbook/4.5.nix { }; + + docbook_xml_ebnf_dtd = callPackage ../data/sgml+xml/schemas/xml-dtd/docbook-ebnf { }; + + inherit (callPackages ../data/sgml+xml/stylesheets/xslt/docbook-xsl { }) + docbook-xsl-nons + docbook-xsl-ns; + + # TODO: move this to aliases + docbook_xsl = docbook-xsl-nons; + docbook_xsl_ns = docbook-xsl-ns; + + documentation-highlighter = callPackage ../misc/documentation-highlighter { }; + + documize-community = callPackage ../servers/documize-community { }; + + doge = callPackage ../misc/doge { }; + + doulos-sil = callPackage ../data/fonts/doulos-sil { }; + + cabin = callPackage ../data/fonts/cabin { }; + + camingo-code = callPackage ../data/fonts/camingo-code { }; + + combinatorial_designs = callPackage ../data/misc/combinatorial_designs { }; + + conway_polynomials = callPackage ../data/misc/conway_polynomials { }; + + cooper-hewitt = callPackage ../data/fonts/cooper-hewitt { }; + + d2coding = callPackage ../data/fonts/d2coding { }; + + dosis = callPackage ../data/fonts/dosis { }; + + dosemu_fonts = callPackage ../data/fonts/dosemu-fonts { }; + + eb-garamond = callPackage ../data/fonts/eb-garamond { }; + + elliptic_curves = callPackage ../data/misc/elliptic_curves { }; + + eunomia = callPackage ../data/fonts/eunomia { }; + + f5_6 = callPackage ../data/fonts/f5_6 { }; + + faba-icon-theme = callPackage ../data/icons/faba-icon-theme { }; + + faba-mono-icons = callPackage ../data/icons/faba-mono-icons { }; + + ferrum = callPackage ../data/fonts/ferrum { }; + + fixedsys-excelsior = callPackage ../data/fonts/fixedsys-excelsior { }; + + graphs = callPackage ../data/misc/graphs { }; + + emacs-all-the-icons-fonts = callPackage ../data/fonts/emacs-all-the-icons-fonts { }; + + emojione = callPackage ../data/fonts/emojione { + inherit (nodePackages) svgo; + }; + + encode-sans = callPackage ../data/fonts/encode-sans { }; + + envypn-font = callPackage ../data/fonts/envypn-font { }; + + envdir = callPackage ../tools/misc/envdir-go { }; + + fantasque-sans-mono = callPackage ../data/fonts/fantasque-sans-mono {}; + + fira = callPackage ../data/fonts/fira { }; + + fira-code = callPackage ../data/fonts/fira-code { }; + fira-code-symbols = callPackage ../data/fonts/fira-code/symbols.nix { }; + + fira-mono = callPackage ../data/fonts/fira-mono { }; + + font-awesome_4 = (callPackage ../data/fonts/font-awesome-5 { }).v4; + font-awesome_5 = (callPackage ../data/fonts/font-awesome-5 { }).v5; + font-awesome = font-awesome_5; + + freefont_ttf = callPackage ../data/fonts/freefont-ttf { }; + + freepats = callPackage ../data/misc/freepats { }; + + gentium = callPackage ../data/fonts/gentium {}; + + gentium-book-basic = callPackage ../data/fonts/gentium-book-basic {}; + + geolite-legacy = callPackage ../data/misc/geolite-legacy { }; + + gohufont = callPackage ../data/fonts/gohufont { }; + + gnome_user_docs = callPackage ../data/documentation/gnome-user-docs { }; + + gsettings-desktop-schemas = callPackage ../development/libraries/gsettings-desktop-schemas { }; + + go-font = callPackage ../data/fonts/go-font { }; + + greybird = callPackage ../data/themes/greybird { }; + + gyre-fonts = callPackage ../data/fonts/gyre {}; + + hack-font = callPackage ../data/fonts/hack { }; + + helvetica-neue-lt-std = callPackage ../data/fonts/helvetica-neue-lt-std { }; + + hetzner-kube = callPackage ../applications/networking/cluster/hetzner-kube { }; + + hicolor-icon-theme = callPackage ../data/icons/hicolor-icon-theme { }; + + hanazono = callPackage ../data/fonts/hanazono { }; + + hermit = callPackage ../data/fonts/hermit { }; + + hyperscrypt-font = callPackage ../data/fonts/hyperscrypt { }; + + ia-writer-duospace = callPackage ../data/fonts/ia-writer-duospace { }; + + ibm-plex = callPackage ../data/fonts/ibm-plex { }; + + iconpack-obsidian = callPackage ../data/icons/iconpack-obsidian { }; + + inconsolata = callPackage ../data/fonts/inconsolata {}; + inconsolata-lgc = callPackage ../data/fonts/inconsolata/lgc.nix {}; + + input-fonts = callPackage ../data/fonts/input-fonts { }; + + inriafonts = callPackage ../data/fonts/inriafonts { }; + + + iosevka = callPackage ../data/fonts/iosevka { + nodejs = nodejs-10_x; + }; + iosevka-bin = callPackage ../data/fonts/iosevka/bin.nix {}; + + ipafont = callPackage ../data/fonts/ipafont {}; + ipaexfont = callPackage ../data/fonts/ipaexfont {}; + + iwona = callPackage ../data/fonts/iwona { }; + + jost = callPackage ../data/fonts/jost { }; + + joypixels = callPackage ../data/fonts/joypixels { }; + + junicode = callPackage ../data/fonts/junicode { }; + + kanji-stroke-order-font = callPackage ../data/fonts/kanji-stroke-order-font {}; + + kawkab-mono-font = callPackage ../data/fonts/kawkab-mono {}; + + kochi-substitute = callPackage ../data/fonts/kochi-substitute {}; + + kochi-substitute-naga10 = callPackage ../data/fonts/kochi-substitute-naga10 {}; + + latinmodern-math = callPackage ../data/fonts/lm-math {}; + + lato = callPackage ../data/fonts/lato {}; + + league-of-moveable-type = callPackage ../data/fonts/league-of-moveable-type {}; + + ledger-udev-rules = callPackage ../os-specific/linux/ledger-udev-rules {}; + + inherit (callPackages ../data/fonts/redhat-liberation-fonts { }) + liberation_ttf_v1 + liberation_ttf_v2 + ; + liberation_ttf = liberation_ttf_v2; + + liberation-sans-narrow = callPackage ../data/fonts/liberation-sans-narrow { }; + + liberastika = callPackage ../data/fonts/liberastika { }; + + libertine = callPackage ../data/fonts/libertine { }; + + libertinus = callPackage ../data/fonts/libertinus { }; + + libratbag = callPackage ../os-specific/linux/libratbag { }; + + libre-baskerville = callPackage ../data/fonts/libre-baskerville { }; + + libre-bodoni = callPackage ../data/fonts/libre-bodoni { }; + + libre-caslon = callPackage ../data/fonts/libre-caslon { }; + + libre-franklin = callPackage ../data/fonts/libre-franklin { }; + + lmmath = callPackage ../data/fonts/lmodern/lmmath.nix {}; + + lmodern = callPackage ../data/fonts/lmodern { }; + + lobster-two = callPackage ../data/fonts/lobster-two {}; + + logitech-udev-rules = callPackage ../os-specific/linux/logitech-udev-rules {}; + + # lohit-fonts.assamese lohit-fonts.bengali lohit-fonts.devanagari lohit-fonts.gujarati lohit-fonts.gurmukhi + # lohit-fonts.kannada lohit-fonts.malayalam lohit-fonts.marathi lohit-fonts.nepali lohit-fonts.odia + # lohit-fonts.tamil-classical lohit-fonts.tamil lohit-fonts.telugu + # lohit-fonts.kashmiri lohit-fonts.konkani lohit-fonts.maithili lohit-fonts.sindhi + lohit-fonts = recurseIntoAttrs ( callPackages ../data/fonts/lohit-fonts { } ); + + luculent = callPackage ../data/fonts/luculent { }; + + maia-icon-theme = callPackage ../data/icons/maia-icon-theme { }; + + mailcap = callPackage ../data/misc/mailcap { }; + + marathi-cursive = callPackage ../data/fonts/marathi-cursive { }; + + man-pages = callPackage ../data/documentation/man-pages { }; + + manrope = callPackage ../data/fonts/manrope { }; + + matcha = callPackage ../data/themes/matcha { }; + + materia-theme = callPackage ../data/themes/materia-theme { }; + + material-design-icons = callPackage ../data/fonts/material-design-icons { }; + + material-icons = callPackage ../data/fonts/material-icons { }; + + meslo-lg = callPackage ../data/fonts/meslo-lg {}; + + migmix = callPackage ../data/fonts/migmix {}; + + migu = callPackage ../data/fonts/migu {}; + + miscfiles = callPackage ../data/misc/miscfiles { }; + + media-player-info = callPackage ../data/misc/media-player-info {}; + + medio = callPackage ../data/fonts/medio { }; + + mno16 = callPackage ../data/fonts/mno16 { }; + + mnist = callPackage ../data/machine-learning/mnist { }; + + mobile-broadband-provider-info = callPackage ../data/misc/mobile-broadband-provider-info { }; + + mojave-gtk-theme = callPackage ../data/themes/mojave { }; + + moka-icon-theme = callPackage ../data/icons/moka-icon-theme { }; + + monoid = callPackage ../data/fonts/monoid { }; + + mononoki = callPackage ../data/fonts/mononoki { }; + + montserrat = callPackage ../data/fonts/montserrat { }; + + mph_2b_damase = callPackage ../data/fonts/mph-2b-damase { }; + + mplus-outline-fonts = callPackage ../data/fonts/mplus-outline-fonts { }; + + mro-unicode = callPackage ../data/fonts/mro-unicode { }; + + mustache-spec = callPackage ../data/documentation/mustache-spec { }; + + mustache-go = callPackage ../development/tools/mustache-go { }; + + myrica = callPackage ../data/fonts/myrica { }; + + nafees = callPackage ../data/fonts/nafees { }; + + nanum-gothic-coding = callPackage ../data/fonts/nanum-gothic-coding { }; + + national-park-typeface = callPackage ../data/fonts/national-park { }; + + nordic = callPackage ../data/themes/nordic { }; + + nordic-polar = callPackage ../data/themes/nordic-polar { }; + + inherit (callPackages ../data/fonts/noto-fonts {}) + noto-fonts noto-fonts-cjk noto-fonts-emoji noto-fonts-extra; + + nullmailer = callPackage ../servers/mail/nullmailer { + stdenv = gccStdenv; + }; + + numix-icon-theme = callPackage ../data/icons/numix-icon-theme { }; + + numix-icon-theme-circle = callPackage ../data/icons/numix-icon-theme-circle { }; + + numix-icon-theme-square = callPackage ../data/icons/numix-icon-theme-square { }; + + numix-cursor-theme = callPackage ../data/icons/numix-cursor-theme { }; + + office-code-pro = callPackage ../data/fonts/office-code-pro { }; + + oldstandard = callPackage ../data/fonts/oldstandard { }; + + oldsindhi = callPackage ../data/fonts/oldsindhi { }; + + open-dyslexic = callPackage ../data/fonts/open-dyslexic { }; + + open-sans = callPackage ../data/fonts/open-sans { }; + + orbitron = callPackage ../data/fonts/orbitron { }; + + overpass = callPackage ../data/fonts/overpass { }; + + oxygenfonts = callPackage ../data/fonts/oxygenfonts { }; + + inherit (kdeFrameworks) oxygen-icons5; + + paper-icon-theme = callPackage ../data/icons/paper-icon-theme { }; + + papirus-icon-theme = callPackage ../data/icons/papirus-icon-theme { }; + + papis = with python3Packages; toPythonApplication papis; + + paps = callPackage ../tools/misc/paps { }; + + pecita = callPackage ../data/fonts/pecita {}; + + paratype-pt-mono = callPackage ../data/fonts/paratype-pt/mono.nix {}; + paratype-pt-sans = callPackage ../data/fonts/paratype-pt/sans.nix {}; + paratype-pt-serif = callPackage ../data/fonts/paratype-pt/serif.nix {}; + + pari-galdata = callPackage ../data/misc/pari-galdata {}; + + pari-seadata-small = callPackage ../data/misc/pari-seadata-small {}; + + penna = callPackage ../data/fonts/penna { }; + + plano-theme = callPackage ../data/themes/plano { }; + + plata-theme = callPackage ../data/themes/plata { + inherit (mate) marco; + }; + + poly = callPackage ../data/fonts/poly { }; + + polytopes_db = callPackage ../data/misc/polytopes_db { }; + + posix_man_pages = callPackage ../data/documentation/man-pages-posix { }; + + powerline-fonts = callPackage ../data/fonts/powerline-fonts { }; + + powerline-go = callPackage ../tools/misc/powerline-go { }; + + powerline-rs = callPackage ../tools/misc/powerline-rs { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + profont = callPackage ../data/fonts/profont { }; + + proggyfonts = callPackage ../data/fonts/proggyfonts { }; + + public-sans = callPackage ../data/fonts/public-sans { }; + + publicsuffix-list = callPackage ../data/misc/publicsuffix-list { }; + + qogir-theme = callPackage ../data/themes/qogir { }; + + redhat-official-fonts = callPackage ../data/fonts/redhat-official { }; + + route159 = callPackage ../data/fonts/route159 { }; + + sampradaya = callPackage ../data/fonts/sampradaya { }; + + sarasa-gothic = callPackage ../data/fonts/sarasa-gothic { }; + + scowl = callPackage ../data/misc/scowl { }; + + seshat = callPackage ../data/fonts/seshat { }; + + shaderc = callPackage ../development/compilers/shaderc { }; + + shades-of-gray-theme = callPackage ../data/themes/shades-of-gray { }; + + mime-types = callPackage ../data/misc/mime-types { }; + + shared-mime-info = callPackage ../data/misc/shared-mime-info { }; + + shared_desktop_ontologies = callPackage ../data/misc/shared-desktop-ontologies { }; + + scheherazade = callPackage ../data/fonts/scheherazade { }; + + signwriting = callPackage ../data/fonts/signwriting { }; + + sierra-gtk-theme = callPackage ../data/themes/sierra { }; + + soundfont-fluid = callPackage ../data/soundfonts/fluid { }; + + stdmanpages = callPackage ../data/documentation/std-man-pages { }; + + starship = callPackage ../tools/misc/starship { }; + + stix-otf = callPackage ../data/fonts/stix-otf { }; + + stix-two = callPackage ../data/fonts/stix-two { }; + + inherit (callPackages ../data/fonts/gdouros { }) + aegan aegyptus akkadian assyrian eemusic maya symbola textfonts unidings; + + iana-etc = callPackage ../data/misc/iana-etc { }; + + poppler_data = callPackage ../data/misc/poppler-data { }; + + qgo = libsForQt5.callPackage ../games/qgo { }; + + qmc2 = libsForQt5.callPackage ../misc/emulators/qmc2 { }; + + quattrocento = callPackage ../data/fonts/quattrocento {}; + + quattrocento-sans = callPackage ../data/fonts/quattrocento-sans {}; + + r3rs = callPackage ../data/documentation/rnrs/r3rs.nix { }; + + r4rs = callPackage ../data/documentation/rnrs/r4rs.nix { }; + + r5rs = callPackage ../data/documentation/rnrs/r5rs.nix { }; + + raleway = callPackage ../data/fonts/raleway { }; + + rictydiminished-with-firacode = callPackage ../data/fonts/rictydiminished-with-firacode { }; + + roboto = callPackage ../data/fonts/roboto { }; + + roboto-mono = callPackage ../data/fonts/roboto-mono { }; + + roboto-slab = callPackage ../data/fonts/roboto-slab { }; + + hasklig = callPackage ../data/fonts/hasklig {}; + + interfacer = callPackage ../development/tools/interfacer { }; + + maligned = callPackage ../development/tools/maligned { }; + + inter-ui = callPackage ../data/fonts/inter-ui { }; + inter = callPackage ../data/fonts/inter { }; + + siji = callPackage ../data/fonts/siji { }; + + sound-theme-freedesktop = callPackage ../data/misc/sound-theme-freedesktop { }; + + source-code-pro = callPackage ../data/fonts/source-code-pro {}; + + source-sans-pro = callPackage ../data/fonts/source-sans-pro { }; + + source-serif-pro = callPackage ../data/fonts/source-serif-pro { }; + + source-han-code-jp = callPackage ../data/fonts/source-han-code-jp { }; + + sourceHanSansPackages = dontRecurseIntoAttrs (callPackage ../data/fonts/source-han-sans { }); + source-han-sans-japanese = sourceHanSansPackages.japanese; + source-han-sans-korean = sourceHanSansPackages.korean; + source-han-sans-simplified-chinese = sourceHanSansPackages.simplified-chinese; + source-han-sans-traditional-chinese = sourceHanSansPackages.traditional-chinese; + sourceHanSerifPackages = dontRecurseIntoAttrs (callPackage ../data/fonts/source-han-serif { }); + source-han-serif-japanese = sourceHanSerifPackages.japanese; + source-han-serif-korean = sourceHanSerifPackages.korean; + source-han-serif-simplified-chinese = sourceHanSerifPackages.simplified-chinese; + source-han-serif-traditional-chinese = sourceHanSerifPackages.traditional-chinese; + + spleen = callPackage ../data/fonts/spleen { }; + + stilo-themes = callPackage ../data/themes/stilo { }; + + sudo-font = callPackage ../data/fonts/sudo { }; + + inherit (callPackages ../data/fonts/tai-languages { }) tai-ahom; + + tamsyn = callPackage ../data/fonts/tamsyn { }; + + tango-icon-theme = callPackage ../data/icons/tango-icon-theme { + gtk = res.gtk2; + }; + + themes = name: callPackage (../data/misc/themes + ("/" + name + ".nix")) {}; + + theano = callPackage ../data/fonts/theano { }; + + template-glib = callPackage ../development/libraries/template-glib { }; + + tempora_lgc = callPackage ../data/fonts/tempora-lgc { }; + + tenderness = callPackage ../data/fonts/tenderness { }; + + terminus_font = callPackage ../data/fonts/terminus-font { }; + + terminus_font_ttf = callPackage ../data/fonts/terminus-font-ttf { }; + + termtekst = callPackage ../misc/emulators/termtekst { }; + + tex-gyre = callPackages ../data/fonts/tex-gyre { }; + + tex-gyre-math = callPackages ../data/fonts/tex-gyre-math { }; + + tipa = callPackage ../data/fonts/tipa { }; + + ttf_bitstream_vera = callPackage ../data/fonts/ttf-bitstream-vera { }; + + ttf-envy-code-r = callPackage ../data/fonts/ttf-envy-code-r {}; + + twemoji-color-font = callPackage ../data/fonts/twemoji-color-font { + inherit (nodePackages) svgo; + }; + + tzdata = callPackage ../data/misc/tzdata { }; + + ubuntu_font_family = callPackage ../data/fonts/ubuntu-font-family { }; + + ucs-fonts = callPackage ../data/fonts/ucs-fonts { }; + + ultimate-oldschool-pc-font-pack = callPackage ../data/fonts/ultimate-oldschool-pc-font-pack { }; + + undefined-medium = callPackage ../data/fonts/undefined-medium { }; + + uni-vga = callPackage ../data/fonts/uni-vga { }; + + unifont = callPackage ../data/fonts/unifont { }; + + unifont_upper = callPackage ../data/fonts/unifont_upper { }; + + unscii = callPackage ../data/fonts/unscii { }; + + vanilla-dmz = callPackage ../data/icons/vanilla-dmz { }; + + vdrsymbols = callPackage ../data/fonts/vdrsymbols { }; + + vegur = callPackage ../data/fonts/vegur { }; + + victor-mono = callPackage ../data/fonts/victor-mono { }; + + vistafonts = callPackage ../data/fonts/vista-fonts { }; + + vistafonts-chs = callPackage ../data/fonts/vista-fonts-chs { }; + + weather-icons = callPackage ../data/fonts/weather-icons { }; + + wireless-regdb = callPackage ../data/misc/wireless-regdb { }; + + wqy_microhei = callPackage ../data/fonts/wqy-microhei { }; + + wqy_zenhei = callPackage ../data/fonts/wqy-zenhei { }; + + xhtml1 = callPackage ../data/sgml+xml/schemas/xml-dtd/xhtml1 { }; + + xits-math = callPackage ../data/fonts/xits-math { }; + + xkcd-font = callPackage ../data/fonts/xkcd-font { }; + + xkeyboard_config = xorg.xkeyboardconfig; + + xlsx2csv = with python3Packages; toPythonApplication xlsx2csv; + + xorg-rgb = callPackage ../data/misc/xorg-rgb {}; + + yanone-kaffeesatz = callPackage ../data/fonts/yanone-kaffeesatz {}; + + zafiro-icons = callPackage ../data/icons/zafiro-icons { }; + + zeal = libsForQt5.callPackage ../data/documentation/zeal { }; + + zilla-slab = callPackage ../data/fonts/zilla-slab { }; + + zuki-themes = callPackage ../data/themes/zuki { }; + + + ### APPLICATIONS + + _2bwm = callPackage ../applications/window-managers/2bwm { + patches = config."2bwm".patches or []; + }; + + a2jmidid = callPackage ../applications/audio/a2jmidid { }; + + aacgain = callPackage ../applications/audio/aacgain { }; + + abcde = callPackage ../applications/audio/abcde { + inherit (pythonPackages) eyeD3; + }; + + abiword = callPackage ../applications/office/abiword { }; + + abook = callPackage ../applications/misc/abook { }; + + acd-cli = callPackage ../applications/networking/sync/acd_cli { + inherit (python3Packages) + buildPythonApplication appdirs colorama dateutil + requests requests_toolbelt sqlalchemy fusepy; + }; + + adobe-reader = pkgsi686Linux.callPackage ../applications/misc/adobe-reader { }; + + masterpdfeditor = libsForQt5.callPackage ../applications/misc/masterpdfeditor { }; + + aeolus = callPackage ../applications/audio/aeolus { }; + + aewan = callPackage ../applications/editors/aewan { }; + + afterstep = callPackage ../applications/window-managers/afterstep { + fltk = fltk13; + gtk = gtk2; + stdenv = gcc49Stdenv; + }; + + agedu = callPackage ../tools/misc/agedu { }; + + ahoviewer = callPackage ../applications/graphics/ahoviewer { }; + + airwave = callPackage ../applications/audio/airwave { }; + + alembic = callPackage ../development/libraries/alembic {}; + + alchemy = callPackage ../applications/graphics/alchemy { }; + + alock = callPackage ../misc/screensavers/alock { }; + + inherit (python3Packages) alot; + + alpine = callPackage ../applications/networking/mailreaders/alpine { + tcl = tcl-8_5; + }; + + msgviewer = callPackage ../applications/networking/mailreaders/msgviewer { }; + + amarok = libsForQt5.callPackage ../applications/audio/amarok { }; + amarok-kf5 = amarok; # for compatibility + + AMB-plugins = callPackage ../applications/audio/AMB-plugins { }; + + ams-lv2 = callPackage ../applications/audio/ams-lv2 { }; + + amsn = callPackage ../applications/networking/instant-messengers/amsn { }; + + androidStudioPackages = recurseIntoAttrs + (callPackage ../applications/editors/android-studio { }); + android-studio = androidStudioPackages.stable; + + animbar = callPackage ../applications/graphics/animbar { }; + + antfs-cli = callPackage ../applications/misc/antfs-cli {}; + + antimony = libsForQt5.callPackage ../applications/graphics/antimony {}; + + antiword = callPackage ../applications/office/antiword {}; + + ao = libfive; + + apache-directory-studio = callPackage ../applications/networking/apache-directory-studio {}; + + appeditor = callPackage ../applications/misc/appeditor { }; + + aqemu = libsForQt5.callPackage ../applications/virtualization/aqemu { }; + + ardour = callPackage ../applications/audio/ardour { + inherit (gnome2) libgnomecanvas libgnomecanvasmm; + inherit (vamp) vampSDK; + }; + + arelle = with python3Packages; toPythonApplication arelle; + + argo = callPackage ../applications/networking/cluster/argo { }; + + ario = callPackage ../applications/audio/ario { }; + + arora = callPackage ../applications/networking/browsers/arora { }; + + artha = callPackage ../applications/misc/artha { }; + + atlassian-cli = callPackage ../applications/office/atlassian-cli { }; + + atomEnv = callPackage ../applications/editors/atom/env.nix { + gconf = gnome2.GConf; + }; + + atomPackages = dontRecurseIntoAttrs (callPackage ../applications/editors/atom { }); + + inherit (atomPackages) atom atom-beta; + + aseprite = callPackage ../applications/editors/aseprite { }; + aseprite-unfree = aseprite.override { unfree = true; }; + + astroid = callPackage ../applications/networking/mailreaders/astroid { }; + + audacious = callPackage ../applications/audio/audacious { }; + audaciousQt5 = libsForQt5.callPackage ../applications/audio/audacious/qt-5.nix { }; + + audacity = callPackage ../applications/audio/audacity { }; + + audio-recorder = callPackage ../applications/audio/audio-recorder { }; + + autokey = callPackage ../applications/office/autokey { }; + + autotrace = callPackage ../applications/graphics/autotrace {}; + + avocode = callPackage ../applications/graphics/avocode {}; + + cadence = libsForQt5.callPackage ../applications/audio/cadence { }; + + milkytracker = callPackage ../applications/audio/milkytracker { }; + + schismtracker = callPackage ../applications/audio/schismtracker { }; + + altcoins = recurseIntoAttrs ( callPackage ../applications/altcoins { } ); + + bitcoin = altcoins.bitcoin; + clightning = altcoins.clightning; + lnd = altcoins.lnd; + + cryptop = altcoins.cryptop; + + jnetmap = callPackage ../applications/networking/jnetmap {}; + + libbitcoin = callPackage ../tools/misc/libbitcoin/libbitcoin.nix { + secp256k1 = secp256k1.override { enableECDH = true; }; + }; + + libbitcoin-protocol = callPackage ../tools/misc/libbitcoin/libbitcoin-protocol.nix { }; + libbitcoin-client = callPackage ../tools/misc/libbitcoin/libbitcoin-client.nix { }; + libbitcoin-network = callPackage ../tools/misc/libbitcoin/libbitcoin-network.nix { }; + libbitcoin-explorer = callPackage ../tools/misc/libbitcoin/libbitcoin-explorer.nix { }; + + + go-ethereum = res.altcoins.go-ethereum; + ethabi = res.altcoins.ethabi; + + parity = res.altcoins.parity; + parity-beta = res.altcoins.parity-beta; + parity-ui = res.altcoins.parity-ui; + + polkadot = res.altcoins.polkadot; + + stellar-core = res.altcoins.stellar-core; + + particl-core = res.altcoins.particl-core; + + aumix = callPackage ../applications/audio/aumix { + gtkGUI = false; + }; + + autopanosiftc = callPackage ../applications/graphics/autopanosiftc { }; + + aesop = callPackage ../applications/office/aesop { }; + + avidemux = libsForQt5.callPackage ../applications/video/avidemux { }; + + avrdudess = callPackage ../applications/misc/avrdudess { }; + + avxsynth = callPackage ../applications/video/avxsynth { + libjpeg = libjpeg_original; # error: 'JCOPYRIGHT_SHORT' was not declared in this scope + }; + + awesome-4-0 = callPackage ../applications/window-managers/awesome { + cairo = cairo.override { xcbSupport = true; }; + inherit (texFunctions) fontsConf; + }; + awesome = awesome-4-0; + + awesomebump = libsForQt5.callPackage ../applications/graphics/awesomebump { }; + + inherit (gnome3) baobab; + + backintime-common = callPackage ../applications/networking/sync/backintime/common.nix { }; + + backintime-qt4 = callPackage ../applications/networking/sync/backintime/qt4.nix { }; + + backintime = backintime-qt4; + + balsa = callPackage ../applications/networking/mailreaders/balsa { }; + + bandwidth = callPackage ../tools/misc/bandwidth { }; + + baresip = callPackage ../applications/networking/instant-messengers/baresip { }; + + barrier = libsForQt5.callPackage ../applications/misc/barrier {}; + + bashSnippets = callPackage ../applications/misc/bashSnippets { }; + + batik = callPackage ../applications/graphics/batik { }; + + batti = callPackage ../applications/misc/batti { }; + + baudline = callPackage ../applications/audio/baudline { }; + + + bazaar = callPackage ../applications/version-management/bazaar { }; + + bazaarTools = callPackage ../applications/version-management/bazaar/tools.nix { }; + + bb = callPackage ../applications/misc/bb { }; + + beast = callPackage ../applications/audio/beast { + inherit (gnome2) libgnomecanvas libart_lgpl; + guile = guile_1_8; + }; + + bevelbar = callPackage ../applications/window-managers/bevelbar { }; + + bibletime = callPackage ../applications/misc/bibletime { }; + + bino3d = libsForQt5.callPackage ../applications/video/bino3d { + ffmpeg = ffmpeg_4; + glew = glew110; + }; + + bitcoinarmory = callPackage ../applications/misc/bitcoinarmory { pythonPackages = python2Packages; }; + + bitkeeper = callPackage ../applications/version-management/bitkeeper { + gperf = gperf_3_0; + }; + + bitlbee = callPackage ../applications/networking/instant-messengers/bitlbee { }; + bitlbee-plugins = callPackage ../applications/networking/instant-messengers/bitlbee/plugins.nix { }; + + bitlbee-discord = callPackage ../applications/networking/instant-messengers/bitlbee-discord { }; + + bitlbee-facebook = callPackage ../applications/networking/instant-messengers/bitlbee-facebook { }; + + bitlbee-steam = callPackage ../applications/networking/instant-messengers/bitlbee-steam { }; + + bitlbee-mastodon = callPackage ../applications/networking/instant-messengers/bitlbee-mastodon { }; + + bitmeter = callPackage ../applications/audio/bitmeter { }; + + bitscope = recurseIntoAttrs + (callPackage ../applications/science/electronics/bitscope/packages.nix { }); + + bitwig-studio1 = callPackage ../applications/audio/bitwig-studio/bitwig-studio1.nix { + inherit (gnome3) zenity; + libxkbcommon = libxkbcommon_7; + }; + bitwig-studio2 = callPackage ../applications/audio/bitwig-studio/bitwig-studio2.nix { + inherit (pkgs) bitwig-studio1; + }; + bitwig-studio3 = callPackage ../applications/audio/bitwig-studio/bitwig-studio3.nix { + inherit (pkgs) bitwig-studio1; + }; + bitwig-studio = bitwig-studio3; + + bgpdump = callPackage ../tools/networking/bgpdump { }; + + blackbox = callPackage ../applications/version-management/blackbox { }; + + bleachbit = callPackage ../applications/misc/bleachbit { }; + + blender = callPackage ../applications/misc/blender { }; + + bluefish = callPackage ../applications/editors/bluefish { + gtk = gtk3; + }; + + bluejeans = callPackage ../applications/networking/browsers/mozilla-plugins/bluejeans { }; + + bluejeans-gui = callPackage ../applications/networking/instant-messengers/bluejeans { + gconf = pkgs.gnome2.GConf; + inherit (pkgs.xorg) libX11 libXrender libXtst libXdamage + libXi libXext libXfixes libXcomposite; + }; + + bombono = callPackage ../applications/video/bombono {}; + + bomi = libsForQt5.callPackage ../applications/video/bomi { + ffmpeg = ffmpeg_2; + }; + + bonzomatic = callPackage ../applications/editors/bonzomatic { }; + + brackets = callPackage ../applications/editors/brackets { gconf = gnome2.GConf; }; + + brave = callPackage ../applications/networking/browsers/brave { }; + + notmuch-bower = callPackage ../applications/networking/mailreaders/notmuch-bower { }; + + brig = callPackage ../applications/networking/brig { }; + + bristol = callPackage ../applications/audio/bristol { }; + + bs1770gain = callPackage ../applications/audio/bs1770gain { }; + + bspwm = callPackage ../applications/window-managers/bspwm { }; + + btops = callPackage ../applications/window-managers/btops { }; + + bvi = callPackage ../applications/editors/bvi { }; + + bviplus = callPackage ../applications/editors/bviplus { }; + + calf = callPackage ../applications/audio/calf { + inherit (gnome2) libglade; + stdenv = gcc5Stdenv; + }; + + calcurse = callPackage ../applications/misc/calcurse { }; + + calculix = callPackage ../applications/science/math/calculix {}; + + calibre = libsForQt5.callPackage ../applications/misc/calibre { }; + + calligra = libsForQt5.callPackage ../applications/office/calligra { + inherit (kdeApplications) akonadi-calendar akonadi-contacts; + openjpeg = openjpeg_1; + poppler = poppler_0_61; + }; + + perkeep = callPackage ../applications/misc/perkeep { }; + + canto-curses = callPackage ../applications/networking/feedreaders/canto-curses { }; + + canto-daemon = callPackage ../applications/networking/feedreaders/canto-daemon { }; + + carddav-util = callPackage ../tools/networking/carddav-util { }; + + carla = qt5.callPackage ../applications/audio/carla { }; + + catfish = callPackage ../applications/search/catfish { }; + + catimg = callPackage ../tools/misc/catimg { }; + + cava = callPackage ../applications/audio/cava { }; + + cb2bib = libsForQt5.callPackage ../applications/office/cb2bib { }; + + cbatticon = callPackage ../applications/misc/cbatticon { }; + + cbc = callPackage ../applications/science/math/cbc { }; + + cddiscid = callPackage ../applications/audio/cd-discid { + inherit (darwin) IOKit; + }; + + cdparanoia = cdparanoiaIII; + + cdparanoiaIII = callPackage ../applications/audio/cdparanoia { + inherit (darwin) IOKit; + inherit (darwin.apple_sdk.frameworks) Carbon; + }; + + cdrtools = callPackage ../applications/misc/cdrtools { + inherit (darwin.apple_sdk.frameworks) Carbon IOKit; + }; + + centerim = callPackage ../applications/networking/instant-messengers/centerim { }; + + cgit = callPackage ../applications/version-management/git-and-tools/cgit { + inherit (python3Packages) python wrapPython pygments markdown; + }; + + cgminer = callPackage ../applications/misc/cgminer { }; + + chirp = callPackage ../applications/radio/chirp { + inherit (pythonPackages) pyserial pygtk; + }; + + browsh = callPackage ../applications/networking/browsers/browsh { }; + + bookworm = callPackage ../applications/office/bookworm { }; + + chromium = callPackage ../applications/networking/browsers/chromium (config.chromium or {}); + + chronos = callPackage ../applications/networking/cluster/chronos { }; + + chromiumBeta = lowPrio (chromium.override { channel = "beta"; }); + + chromiumDev = lowPrio (chromium.override { channel = "dev"; }); + + chuck = callPackage ../applications/audio/chuck { + inherit (darwin.apple_sdk.frameworks) AppKit Carbon CoreAudio CoreMIDI CoreServices Kernel; + }; + + cinelerra = callPackage ../applications/video/cinelerra { }; + + claws-mail = callPackage ../applications/networking/mailreaders/claws-mail { + inherit (xorg) libSM; + }; + + clfswm = callPackage ../applications/window-managers/clfswm { }; + + clickshare-csc1 = callPackage ../applications/video/clickshare-csc1 { }; + + cligh = python3Packages.callPackage ../development/tools/github/cligh {}; + + clight = callPackage ../applications/misc/clight { }; + + clightd = callPackage ../applications/misc/clight/clightd.nix { }; + + clipgrab = qt5.callPackage ../applications/video/clipgrab { }; + + clipmenu = callPackage ../applications/misc/clipmenu { }; + + clipit = callPackage ../applications/misc/clipit { }; + + cloud-print-connector = callPackage ../servers/cloud-print-connector { }; + + clp = callPackage ../applications/science/math/clp { }; + + cmatrix = callPackage ../applications/misc/cmatrix { }; + + cmus = callPackage ../applications/audio/cmus { + inherit (darwin.apple_sdk.frameworks) CoreAudio; + libjack = libjack2; + ffmpeg = ffmpeg_2; + }; + + cmusfm = callPackage ../applications/audio/cmusfm { }; + + cni = callPackage ../applications/networking/cluster/cni {}; + cni-plugins = callPackage ../applications/networking/cluster/cni/plugins.nix {}; + + cntr = callPackage ../applications/virtualization/cntr { }; + + communi = libsForQt5.callPackage ../applications/networking/irc/communi { }; + + confclerk = callPackage ../applications/misc/confclerk { }; + + copyq = libsForQt5.callPackage ../applications/misc/copyq { }; + + coriander = callPackage ../applications/video/coriander { + inherit (gnome2) libgnomeui GConf; + }; + + csa = callPackage ../applications/audio/csa { }; + + csound = callPackage ../applications/audio/csound { + fluidsynth = fluidsynth_1; + }; + + csound-manual = callPackage ../applications/audio/csound/csound-manual { + python = python27; + pygments = python27Packages.pygments; + }; + + csound-qt = libsForQt59.callPackage ../applications/audio/csound/csound-qt { + python = python27; + }; + + cinepaint = callPackage ../applications/graphics/cinepaint { + fltk = fltk13; + libpng = libpng12; + cmake = cmake_2_8; + }; + + codeblocks = callPackage ../applications/editors/codeblocks { }; + codeblocksFull = codeblocks.override { contribPlugins = true; }; + + comical = callPackage ../applications/graphics/comical { }; + + conkeror-unwrapped = callPackage ../applications/networking/browsers/conkeror { }; + conkeror = wrapFirefox conkeror-unwrapped { }; + + containerd = callPackage ../applications/virtualization/containerd { }; + + convchain = callPackage ../tools/graphics/convchain {}; + + coursera-dl = callPackage ../applications/misc/coursera-dl {}; + + coyim = callPackage ../applications/networking/instant-messengers/coyim {}; + + cpp_ethereum = callPackage ../applications/misc/cpp-ethereum { }; + + csdp = callPackage ../applications/science/math/csdp { }; + + ctop = callPackage ../tools/system/ctop { }; + + cubicsdr = callPackage ../applications/radio/cubicsdr { wxGTK = wxGTK31; }; + + cum = callPackage ../applications/misc/cum { }; + + cuneiform = callPackage ../tools/graphics/cuneiform {}; + + curseradio = callPackage ../applications/audio/curseradio { }; + + cutecom = libsForQt5.callPackage ../tools/misc/cutecom { }; + + cvs = callPackage ../applications/version-management/cvs { }; + + cvsps = callPackage ../applications/version-management/cvsps { }; + + cvs2svn = callPackage ../applications/version-management/cvs2svn { }; + + cwm = callPackage ../applications/window-managers/cwm { }; + + cyclone = callPackage ../applications/audio/pd-plugins/cyclone { }; + + dablin = callPackage ../applications/radio/dablin { }; + + darcs = haskell.lib.overrideCabal (haskell.lib.justStaticExecutables haskellPackages.darcs) (drv: { + configureFlags = (stdenv.lib.remove "-flibrary" drv.configureFlags or []) ++ ["-f-library"]; + }); + + darktable = callPackage ../applications/graphics/darktable { + lua = lua5_3; + pugixml = pugixml.override { shared = true; }; + }; + + das_watchdog = callPackage ../tools/system/das_watchdog { }; + + dbvisualizer = callPackage ../applications/misc/dbvisualizer {}; + + dd-agent = callPackage ../tools/networking/dd-agent/5.nix { }; + datadog-agent = callPackage ../tools/networking/dd-agent/datadog-agent.nix { + pythonPackages = datadog-integrations-core {}; + }; + datadog-process-agent = callPackage ../tools/networking/dd-agent/datadog-process-agent.nix { }; + datadog-integrations-core = extras: callPackage ../tools/networking/dd-agent/integrations-core.nix { + python = python27; + extraIntegrations = extras; + }; + + ddgr = callPackage ../applications/misc/ddgr { }; + + deadbeef = callPackage ../applications/audio/deadbeef { }; + + deadbeefPlugins = { + headerbar-gtk3 = callPackage ../applications/audio/deadbeef/plugins/headerbar-gtk3.nix { }; + infobar = callPackage ../applications/audio/deadbeef/plugins/infobar.nix { }; + lyricbar = callPackage ../applications/audio/deadbeef/plugins/lyricbar.nix { }; + mpris2 = callPackage ../applications/audio/deadbeef/plugins/mpris2.nix { }; + }; + + deadbeef-with-plugins = callPackage ../applications/audio/deadbeef/wrapper.nix { + plugins = []; + }; + + dfasma = libsForQt5.callPackage ../applications/audio/dfasma { }; + + dfilemanager = libsForQt5.callPackage ../applications/misc/dfilemanager { }; + + dia = callPackage ../applications/graphics/dia { + inherit (pkgs.gnome2) libart_lgpl libgnomeui; + }; + + diffuse = callPackage ../applications/version-management/diffuse { }; + + direwolf = callPackage ../applications/misc/direwolf { }; + + dirt = callPackage ../applications/audio/dirt {}; + + distrho = callPackage ../applications/audio/distrho {}; + + dit = callPackage ../applications/editors/dit { }; + + djvulibre = callPackage ../applications/misc/djvulibre { }; + + djvu2pdf = callPackage ../tools/typesetting/djvu2pdf { }; + + djview = callPackage ../applications/graphics/djview { }; + djview4 = pkgs.djview; + + dmenu = callPackage ../applications/misc/dmenu { }; + + # TODO (@primeos): Remove after the 19.09 branch-off: + dmenu2 = throw '' + The fork "dmenu2" is not maintained by upstream anymore. Please use the + original "dmenu" instead. + ''; + + dmensamenu = callPackage ../applications/misc/dmensamenu { + inherit (python3Packages) buildPythonApplication requests; + }; + + dmrconfig = callPackage ../applications/radio/dmrconfig { }; + + dmtx-utils = callPackage (callPackage ../tools/graphics/dmtx-utils) { + }; + + inherit (callPackage ../applications/virtualization/docker {}) + docker_18_09 + docker_19_03; + + docker = docker_19_03; + docker-edge = docker_19_03; + + docker-proxy = callPackage ../applications/virtualization/docker/proxy.nix { }; + + docker-gc = callPackage ../applications/virtualization/docker/gc.nix { }; + + docker-machine = callPackage ../applications/networking/cluster/docker-machine { }; + docker-machine-kvm = callPackage ../applications/networking/cluster/docker-machine/kvm.nix { }; + docker-machine-kvm2 = callPackage ../applications/networking/cluster/docker-machine/kvm2.nix { }; + docker-machine-xhyve = callPackage ../applications/networking/cluster/docker-machine/xhyve.nix { + inherit (darwin.apple_sdk.frameworks) Hypervisor vmnet; + }; + + docker-distribution = callPackage ../applications/virtualization/docker/distribution.nix { }; + + amazon-ecr-credential-helper = callPackage ../tools/admin/amazon-ecr-credential-helper { }; + + docker-credential-gcr = callPackage ../tools/admin/docker-credential-gcr { }; + + doodle = callPackage ../applications/search/doodle { }; + + dr14_tmeter = callPackage ../applications/audio/dr14_tmeter { }; + + draftsight = callPackage ../applications/graphics/draftsight { }; + + dragonfly-reverb = callPackage ../applications/audio/dragonfly-reverb { }; + + drawio = callPackage ../applications/graphics/drawio {}; + + drawpile = libsForQt5.callPackage ../applications/graphics/drawpile { }; + drawpile-server-headless = libsForQt5.callPackage ../applications/graphics/drawpile { + buildClient = false; + buildServerGui = false; + }; + + droopy = callPackage ../applications/networking/droopy { + inherit (python3Packages) wrapPython; + }; + + drumgizmo = callPackage ../applications/audio/drumgizmo { }; + + dunst = callPackage ../applications/misc/dunst { }; + + du-dust = callPackage ../tools/misc/dust { }; + + devede = callPackage ../applications/video/devede { }; + + denemo = callPackage ../applications/audio/denemo { }; + + dvb_apps = callPackage ../applications/video/dvb-apps { }; + + dvdauthor = callPackage ../applications/video/dvdauthor { }; + + dvdbackup = callPackage ../applications/video/dvdbackup { }; + + dvd-slideshow = callPackage ../applications/video/dvd-slideshow { }; + + dvdstyler = callPackage ../applications/video/dvdstyler { + inherit (gnome2) libgnomeui; + }; + + dwm = callPackage ../applications/window-managers/dwm { + patches = config.dwm.patches or []; + }; + + dwm-git = callPackage ../applications/window-managers/dwm/git.nix { + patches = config.dwm.patches or []; + conf = config.dwm.conf or null; + }; + + dwm-status = callPackage ../applications/window-managers/dwm/dwm-status.nix { }; + + dynamips = callPackage ../applications/virtualization/dynamips { }; + + evilwm = callPackage ../applications/window-managers/evilwm { + patches = config.evilwm.patches or []; + }; + + dzen2 = callPackage ../applications/window-managers/dzen2 { }; + + eaglemode = callPackage ../applications/misc/eaglemode { }; + + echoip = callPackage ../servers/echoip { }; + + eclipses = recurseIntoAttrs (callPackage ../applications/editors/eclipse { + jdk = jdk11; + }); + + ecs-agent = callPackage ../applications/virtualization/ecs-agent { }; + + ed = callPackage ../applications/editors/ed { }; + + edbrowse = callPackage ../applications/editors/edbrowse { }; + + ekho = callPackage ../applications/audio/ekho { }; + + electron-cash = libsForQt5.callPackage ../applications/misc/electron-cash { }; + + electrum = callPackage ../applications/misc/electrum { }; + + electrum-dash = callPackage ../applications/misc/electrum/dash.nix { }; + + electrum-ltc = callPackage ../applications/misc/electrum/ltc.nix { }; + + elinks = callPackage ../applications/networking/browsers/elinks { + openssl = openssl_1_0_2; + }; + + elvis = callPackage ../applications/editors/elvis { }; + + emacs = emacs26; + emacsPackages = emacs26Packages; + emacsPackagesNg = emacs26PackagesNg; + + emacs26 = callPackage ../applications/editors/emacs { + # use override to enable additional features + libXaw = xorg.libXaw; + Xaw3d = null; + gconf = null; + alsaLib = null; + imagemagick = null; + acl = null; + gpm = null; + inherit (darwin.apple_sdk.frameworks) AppKit GSS ImageIO; + }; + + emacs26-nox = lowPrio (appendToName "nox" (emacs26.override { + withX = false; + withGTK2 = false; + withGTK3 = false; + })); + + emacs25 = callPackage ../applications/editors/emacs/25.nix { + # use override to enable additional features + libXaw = xorg.libXaw; + Xaw3d = null; + gconf = null; + alsaLib = null; + imagemagick = null; + acl = null; + gpm = null; + inherit (darwin.apple_sdk.frameworks) AppKit GSS ImageIO; + }; + + emacs25-nox = lowPrio (appendToName "nox" (emacs25.override { + withX = false; + withGTK2 = false; + withGTK3 = false; + })); + + emacsMacport = callPackage ../applications/editors/emacs/macport.nix { + inherit (darwin.apple_sdk.frameworks) + AppKit Carbon Cocoa IOKit OSAKit Quartz QuartzCore WebKit + ImageCaptureCore GSS ImageIO; + stdenv = if stdenv.cc.isClang then llvmPackages_6.stdenv else stdenv; + }; + + emacsPackagesFor = emacs: self: let callPackage = newScope self; in rec { + inherit emacs; + + autoComplete = callPackage ../applications/editors/emacs-modes/auto-complete { }; + + bbdb = callPackage ../applications/editors/emacs-modes/bbdb { }; + + bbdb3 = callPackage ../applications/editors/emacs-modes/bbdb/3.nix {}; + + cedet = callPackage ../applications/editors/emacs-modes/cedet { }; + + calfw = callPackage ../applications/editors/emacs-modes/calfw { }; + + cedille = callPackage ../applications/editors/emacs-modes/cedille { cedille = pkgs.cedille; }; + + coffee = callPackage ../applications/editors/emacs-modes/coffee { }; + + colorTheme = callPackage ../applications/editors/emacs-modes/color-theme { }; + + colorThemeSolarized = callPackage ../applications/editors/emacs-modes/color-theme-solarized { }; + + cryptol = callPackage ../applications/editors/emacs-modes/cryptol { }; + + cua = callPackage ../applications/editors/emacs-modes/cua { }; + + d = callPackage ../applications/editors/emacs-modes/d { }; + + darcsum = callPackage ../applications/editors/emacs-modes/darcsum { }; + + # ecb = callPackage ../applications/editors/emacs-modes/ecb { }; + + emacsClangCompleteAsync = callPackage ../applications/editors/emacs-modes/emacs-clang-complete-async { }; + + emacsSessionManagement = callPackage ../applications/editors/emacs-modes/session-management-for-emacs { }; + + emacsw3m = callPackage ../applications/editors/emacs-modes/emacs-w3m { }; + + emms = callPackage ../applications/editors/emacs-modes/emms { }; + + ensime = callPackage ../applications/editors/emacs-modes/ensime { }; + + erlangMode = callPackage ../applications/editors/emacs-modes/erlang { }; + + ess = callPackage ../applications/editors/emacs-modes/ess { }; + + flymakeCursor = callPackage ../applications/editors/emacs-modes/flymake-cursor { }; + + gh = callPackage ../applications/editors/emacs-modes/gh { }; + + graphvizDot = callPackage ../applications/editors/emacs-modes/graphviz-dot { }; + + gist = callPackage ../applications/editors/emacs-modes/gist { }; + + haskellMode = callPackage ../applications/editors/emacs-modes/haskell { }; + + hsc3Mode = callPackage ../applications/editors/emacs-modes/hsc3 { }; + + hol_light_mode = callPackage ../applications/editors/emacs-modes/hol_light { }; + + htmlize = callPackage ../applications/editors/emacs-modes/htmlize { }; + + ido-ubiquitous = callPackage ../applications/editors/emacs-modes/ido-ubiquitous { }; + + icicles = callPackage ../applications/editors/emacs-modes/icicles { }; + + idris = callPackage ../applications/editors/emacs-modes/idris { }; + + jabber = callPackage ../applications/editors/emacs-modes/jabber { }; + + jade = callPackage ../applications/editors/emacs-modes/jade { }; + + jdee = callPackage ../applications/editors/emacs-modes/jdee { }; + + js2 = callPackage ../applications/editors/emacs-modes/js2 { }; + + let-alist = callPackage ../applications/editors/emacs-modes/let-alist { }; + + logito = callPackage ../applications/editors/emacs-modes/logito { }; + + loremIpsum = callPackage ../applications/editors/emacs-modes/lorem-ipsum { }; + + markdownMode = callPackage ../applications/editors/emacs-modes/markdown-mode { }; + + maudeMode = callPackage ../applications/editors/emacs-modes/maude { }; + + metaweblog = callPackage ../applications/editors/emacs-modes/metaweblog { }; + + monky = callPackage ../applications/editors/emacs-modes/monky { }; + + notmuch = lowPrio (pkgs.notmuch.override { inherit emacs; }); + + ocamlMode = callPackage ../applications/editors/emacs-modes/ocaml { }; + + offlineimap = callPackage ../applications/editors/emacs-modes/offlineimap {}; + + # This is usually a newer version of Org-Mode than that found in GNU Emacs, so + # we want it to have higher precedence. + org = hiPrio (callPackage ../applications/editors/emacs-modes/org { }); + + org2blog = callPackage ../applications/editors/emacs-modes/org2blog { }; + + pcache = callPackage ../applications/editors/emacs-modes/pcache { }; + + phpMode = callPackage ../applications/editors/emacs-modes/php { }; + + prologMode = callPackage ../applications/editors/emacs-modes/prolog { }; + + proofgeneral = callPackage ../applications/editors/emacs-modes/proofgeneral/4.4.nix { + texLive = texlive.combine { inherit (texlive) scheme-basic cm-super ec; }; + }; + proofgeneral_HEAD = callPackage ../applications/editors/emacs-modes/proofgeneral/HEAD.nix { + texinfo = texinfo4 ; + texLive = texlive.combine { inherit (texlive) scheme-basic cm-super ec; }; + }; + + quack = callPackage ../applications/editors/emacs-modes/quack { }; + + rainbowDelimiters = callPackage ../applications/editors/emacs-modes/rainbow-delimiters { }; + + rectMark = callPackage ../applications/editors/emacs-modes/rect-mark { }; + + rudel = callPackage ../applications/editors/emacs-modes/rudel { }; + + s = callPackage ../applications/editors/emacs-modes/s { }; + + sbtMode = callPackage ../applications/editors/emacs-modes/sbt-mode { }; + + scalaMode1 = callPackage ../applications/editors/emacs-modes/scala-mode/v1.nix { }; + scalaMode2 = callPackage ../applications/editors/emacs-modes/scala-mode/v2.nix { }; + + structuredHaskellMode = haskellPackages.structured-haskell-mode; + + sunriseCommander = callPackage ../applications/editors/emacs-modes/sunrise-commander { }; + + tuaregMode = callPackage ../applications/editors/emacs-modes/tuareg { }; + + writeGood = callPackage ../applications/editors/emacs-modes/writegood { }; + + xmlRpc = callPackage ../applications/editors/emacs-modes/xml-rpc { }; + + cask = callPackage ../applications/editors/emacs-modes/cask { }; + }; + + emacs25Packages = dontRecurseIntoAttrs (emacsPackagesFor emacs25 pkgs.emacs25Packages); + emacs26Packages = dontRecurseIntoAttrs (emacsPackagesFor emacs26 pkgs.emacs26Packages); + + emacsPackagesNgFor = emacs: import ./emacs-packages.nix { + inherit lib newScope stdenv pkgs; + inherit fetchFromGitHub fetchurl; + inherit emacs texinfo makeWrapper runCommand writeText; + inherit (xorg) lndir; + + trivialBuild = callPackage ../build-support/emacs/trivial.nix { + inherit emacs; + }; + + melpaBuild = callPackage ../build-support/emacs/melpa.nix { + inherit emacs; + }; + + external = { + inherit (haskellPackages) + ghc-mod structured-haskell-mode Agda hindent; + inherit (pythonPackages) elpy; + inherit + autoconf automake editorconfig-core-c git libffi libpng pkgconfig + poppler rtags w3m zlib substituteAll rustPlatform cmake llvmPackages + libtool zeromq openssl; + }; + }; + + emacs25PackagesNg = dontRecurseIntoAttrs (emacsPackagesNgFor emacs25); + emacs26PackagesNg = dontRecurseIntoAttrs (emacsPackagesNgFor emacs26); + + emacs25WithPackages = emacs25PackagesNg.emacsWithPackages; + emacs26WithPackages = emacs26PackagesNg.emacsWithPackages; + emacsWithPackages = emacsPackagesNg.emacsWithPackages; + + inherit (gnome3) empathy; + + enhanced-ctorrent = callPackage ../applications/networking/enhanced-ctorrent { }; + + eolie = callPackage ../applications/networking/browsers/eolie { }; + + epdfview = callPackage ../applications/misc/epdfview { }; + + epeg = callPackage ../applications/graphics/epeg { }; + + inherit (gnome3) epiphany; + + ephemeral = callPackage ../applications/networking/browsers/ephemeral { }; + + epic5 = callPackage ../applications/networking/irc/epic5 { }; + + eq10q = callPackage ../applications/audio/eq10q { }; + + errbot = callPackage ../applications/networking/errbot { + pythonPackages = python3Packages; + }; + + espeak-classic = callPackage ../applications/audio/espeak { }; + + espeak-ng = callPackage ../applications/audio/espeak-ng { }; + espeak = res.espeak-ng; + + espeakedit = callPackage ../applications/audio/espeak/edit.nix { }; + + esniper = callPackage ../applications/networking/esniper { }; + + eterm = callPackage ../applications/misc/eterm { }; + + eteroj.lv2 = libsForQt5.callPackage ../applications/audio/eteroj.lv2 { }; + + etherape = callPackage ../applications/networking/sniffers/etherape { }; + + evilvte = callPackage ../applications/misc/evilvte (config.evilvte or {}); + + exercism = callPackage ../applications/misc/exercism { }; + + go-motion = callPackage ../development/tools/go-motion { }; + + gpg-mdp = callPackage ../applications/misc/gpg-mdp { }; + + icesl = callPackage ../applications/misc/icesl { }; + + keepassx = callPackage ../applications/misc/keepassx { }; + keepassx2 = callPackage ../applications/misc/keepassx/2.0.nix { }; + keepassxc = libsForQt5.callPackage ../applications/misc/keepassx/community.nix { }; + + inherit (gnome3) evince; + evolution-data-server = gnome3.evolution-data-server; + + keepass = callPackage ../applications/misc/keepass { }; + + keepass-keeagent = callPackage ../applications/misc/keepass-plugins/keeagent { }; + + keepass-keepasshttp = callPackage ../applications/misc/keepass-plugins/keepasshttp { }; + + keepass-keepassrpc = callPackage ../applications/misc/keepass-plugins/keepassrpc { }; + + exrdisplay = callPackage ../applications/graphics/exrdisplay { }; + + exrtools = callPackage ../applications/graphics/exrtools { }; + + fasttext = callPackage ../applications/science/machine-learning/fasttext { }; + + fbpanel = callPackage ../applications/window-managers/fbpanel { }; + + fbreader = callPackage ../applications/misc/fbreader { + inherit (darwin.apple_sdk.frameworks) AppKit Cocoa; + }; + + fdr = libsForQt5.callPackage ../applications/science/programming/fdr { }; + + fehlstart = callPackage ../applications/misc/fehlstart { }; + + fetchmail = callPackage ../applications/misc/fetchmail { + openssl = openssl_1_0_2; + }; + + fff = callPackage ../applications/misc/fff { }; + + fig2dev = callPackage ../applications/graphics/fig2dev { }; + + FIL-plugins = callPackage ../applications/audio/FIL-plugins { }; + + flacon = callPackage ../applications/audio/flacon { }; + + flexget = callPackage ../applications/networking/flexget { }; + + fldigi = callPackage ../applications/radio/fldigi { }; + + flink = callPackage ../applications/networking/cluster/flink { }; + flink_1_5 = flink.override { version = "1.5"; }; + + fllog = callPackage ../applications/radio/fllog { }; + + flmsg = callPackage ../applications/radio/flmsg { }; + + flrig = callPackage ../applications/radio/flrig { }; + + flwrap = callPackage ../applications/radio/flwrap { }; + + fluidsynth = callPackage ../applications/audio/fluidsynth { + inherit (darwin.apple_sdk.frameworks) AudioUnit CoreAudio CoreMIDI CoreServices; + }; + fluidsynth_1 = fluidsynth.override { version = "1"; }; + + fmit = libsForQt5.callPackage ../applications/audio/fmit { }; + + fmsynth = callPackage ../applications/audio/fmsynth { }; + + focuswriter = libsForQt5.callPackage ../applications/editors/focuswriter { }; + + fondo = callPackage ../applications/graphics/fondo { }; + + font-manager = callPackage ../applications/misc/font-manager { }; + + foo-yc20 = callPackage ../applications/audio/foo-yc20 { }; + + fossil = callPackage ../applications/version-management/fossil { }; + + freebayes = callPackage ../applications/science/biology/freebayes { }; + + freewheeling = callPackage ../applications/audio/freewheeling { }; + + fribid = callPackage ../applications/networking/browsers/mozilla-plugins/fribid { + openssl = openssl_1_0_2; + }; + + fritzing = libsForQt5.callPackage ../applications/science/electronics/fritzing { }; + + fsv = callPackage ../applications/misc/fsv { }; + + fvwm = callPackage ../applications/window-managers/fvwm { }; + + ganttproject-bin = callPackage ../applications/misc/ganttproject-bin { }; + + gauche = callPackage ../development/interpreters/gauche { }; + + gcal = callPackage ../applications/misc/gcal { }; + + geany = callPackage ../applications/editors/geany { }; + geany-with-vte = callPackage ../applications/editors/geany/with-vte.nix { }; + + ghostwriter = libsForQt5.callPackage ../applications/editors/ghostwriter { }; + + gitweb = callPackage ../applications/version-management/git-and-tools/gitweb { }; + + gksu = callPackage ../applications/misc/gksu { }; + + gnss-sdr = callPackage ../applications/radio/gnss-sdr { boost=boost166; }; + + gnuradio = callPackage ../applications/radio/gnuradio { + inherit (python2Packages) cheetah lxml Mako matplotlib numpy python pyopengl pyqt4 scipy wxPython pygtk; + inherit (darwin.apple_sdk.frameworks) CoreAudio; + fftw = fftwFloat; + qwt = qwt6_qt4; + }; + + gnuradio-with-packages = callPackage ../applications/radio/gnuradio/wrapper.nix { + inherit (python2Packages) python; + extraPackages = [ gr-nacl gr-osmosdr gr-ais gr-rds ] + ++ lib.optionals stdenv.isLinux [ gr-gsm gr-limesdr ]; + }; + + gr-nacl = callPackage ../applications/radio/gnuradio/nacl.nix { }; + + gr-gsm = callPackage ../applications/radio/gnuradio/gsm.nix { }; + + gr-ais = callPackage ../applications/radio/gnuradio/ais.nix { }; + + gr-limesdr = callPackage ../applications/radio/gnuradio/limesdr.nix { }; + + gr-rds = callPackage ../applications/radio/gnuradio/rds.nix { }; + + gr-osmosdr = callPackage ../applications/radio/gnuradio/osmosdr.nix { }; + + goldendict = libsForQt5.callPackage ../applications/misc/goldendict { }; + + gomuks = callPackage ../applications/networking/instant-messengers/gomuks { }; + + inherit (ocamlPackages) google-drive-ocamlfuse; + + google-musicmanager = callPackage ../applications/audio/google-musicmanager { + inherit (qt5) qtbase qtwebkit; + # Downgrade to 1.34 to get libidn.so.11 + libidn = (libidn.overrideAttrs (oldAttrs: { + src = fetchurl { + url = "mirror://gnu/libidn/libidn-1.34.tar.gz"; + sha256 = "0g3fzypp0xjcgr90c5cyj57apx1cmy0c6y9lvw2qdcigbyby469p"; + }; + })).out; + }; + + googler = callPackage ../applications/misc/googler { + python = python3; + }; + + gopher = callPackage ../applications/networking/gopher/gopher { }; + + gopherclient = libsForQt5.callPackage ../applications/networking/gopher/gopherclient { }; + + goxel = callPackage ../applications/graphics/goxel { }; + + gpa = callPackage ../applications/misc/gpa { }; + + gpicview = callPackage ../applications/graphics/gpicview { + gtk2 = gtk2-x11; + }; + + gpx = callPackage ../applications/misc/gpx { }; + + gqrx = qt5.callPackage ../applications/radio/gqrx { }; + + gpx-viewer = callPackage ../applications/misc/gpx-viewer { }; + + grass = callPackage ../applications/gis/grass { }; + + grepcidr = callPackage ../applications/search/grepcidr { }; + + grepm = callPackage ../applications/search/grepm { }; + + grip = callPackage ../applications/misc/grip { + inherit (gnome2) libgnome libgnomeui vte; + }; + + gsimplecal = callPackage ../applications/misc/gsimplecal { }; + + gthumb = callPackage ../applications/graphics/gthumb { }; + + gtimelog = pythonPackages.gtimelog; + + inherit (gnome3) gucharmap; + + guitarix = callPackage ../applications/audio/guitarix { + fftw = fftwSinglePrec; + }; + + gjay = callPackage ../applications/audio/gjay { }; + + photivo = callPackage ../applications/graphics/photivo { }; + + rhythmbox = callPackage ../applications/audio/rhythmbox { }; + + gradio = callPackage ../applications/audio/gradio { }; + + puddletag = callPackage ../applications/audio/puddletag { }; + + w_scan = callPackage ../applications/video/w_scan { }; + + wavesurfer = callPackage ../applications/misc/audio/wavesurfer { }; + + wavrsocvt = callPackage ../applications/misc/audio/wavrsocvt { }; + + welle-io = libsForQt5.callPackage ../applications/radio/welle-io { }; + + wireshark = callPackage ../applications/networking/sniffers/wireshark { + inherit (darwin.apple_sdk.frameworks) ApplicationServices SystemConfiguration; + }; + wireshark-qt = wireshark; + + # The GTK UI is deprecated by upstream. You probably want the QT version. + wireshark-gtk = throw "Not supported anymore. Use wireshark-qt or wireshark-cli instead."; + wireshark-cli = wireshark.override { withQt = false; }; + + sngrep = callPackage ../applications/networking/sniffers/sngrep {}; + + termshark = callPackage ../tools/networking/termshark { }; + + fbida = callPackage ../applications/graphics/fbida { }; + + fdupes = callPackage ../tools/misc/fdupes { }; + + feh = callPackage ../applications/graphics/feh { }; + + filezilla = callPackage ../applications/networking/ftp/filezilla { }; + + firefoxPackages = recurseIntoAttrs (callPackage ../applications/networking/browsers/firefox/packages.nix { + callPackage = pkgs.newScope { + inherit (gnome2) libIDL; + libpng = libpng_apng; + python = python2; + gnused = gnused_422; + icu = icu63; + inherit (darwin.apple_sdk.frameworks) CoreMedia ExceptionHandling + Kerberos AVFoundation MediaToolbox + CoreLocation Foundation AddressBook; + inherit (darwin) libobjc; + }; + }); + + firefox-unwrapped = firefoxPackages.firefox; + firefox-esr-52-unwrapped = firefoxPackages.firefox-esr-52; + firefox-esr-60-unwrapped = firefoxPackages.firefox-esr-60; + firefox-esr-68-unwrapped = firefoxPackages.firefox-esr-68; + tor-browser-unwrapped = firefoxPackages.tor-browser; + icecat-unwrapped = firefoxPackages.icecat; + + firefox = wrapFirefox firefox-unwrapped { }; + firefox-wayland = wrapFirefox firefox-unwrapped { gdkWayland = true; }; + firefox-esr-52 = wrapFirefox firefox-esr-52-unwrapped { }; + firefox-esr-60 = wrapFirefox firefox-esr-60-unwrapped { }; + firefox-esr-68 = wrapFirefox firefox-esr-68-unwrapped { }; + firefox-esr = firefox-esr-68; + icecat = wrapFirefox icecat-unwrapped { }; + + firefox-bin-unwrapped = callPackage ../applications/networking/browsers/firefox-bin { + channel = "release"; + generated = import ../applications/networking/browsers/firefox-bin/release_sources.nix; + gconf = pkgs.gnome2.GConf; + inherit (pkgs.gnome2) libgnome libgnomeui; + }; + + firefox-bin = wrapFirefox firefox-bin-unwrapped { + browserName = "firefox"; + name = "firefox-bin-" + + (builtins.parseDrvName firefox-bin-unwrapped.name).version; + desktopName = "Firefox"; + }; + + firefox-beta-bin-unwrapped = firefox-bin-unwrapped.override { + channel = "beta"; + generated = import ../applications/networking/browsers/firefox-bin/beta_sources.nix; + gconf = pkgs.gnome2.GConf; + inherit (pkgs.gnome2) libgnome libgnomeui; + }; + + firefox-beta-bin = res.wrapFirefox firefox-beta-bin-unwrapped { + browserName = "firefox"; + name = "firefox-beta-bin-" + + (builtins.parseDrvName firefox-beta-bin-unwrapped.name).version; + desktopName = "Firefox Beta"; + }; + + firefox-devedition-bin-unwrapped = callPackage ../applications/networking/browsers/firefox-bin { + channel = "devedition"; + generated = import ../applications/networking/browsers/firefox-bin/devedition_sources.nix; + gconf = pkgs.gnome2.GConf; + inherit (pkgs.gnome2) libgnome libgnomeui; + }; + + firefox-devedition-bin = res.wrapFirefox firefox-devedition-bin-unwrapped { + browserName = "firefox"; + nameSuffix = "-devedition"; + name = "firefox-devedition-bin-" + + (builtins.parseDrvName firefox-devedition-bin-unwrapped.name).version; + desktopName = "Firefox DevEdition"; + }; + + firestr = libsForQt5.callPackage ../applications/networking/p2p/firestr + { boost = boost155; + }; + + flac = callPackage ../applications/audio/flac { }; + + redoflacs = callPackage ../applications/audio/redoflacs { }; + + flameshot = libsForQt5.callPackage ../tools/misc/flameshot { }; + + flashplayer = callPackage ../applications/networking/browsers/mozilla-plugins/flashplayer (config.flashplayer or {}); + + flashplayer-standalone = callPackage ../applications/networking/browsers/mozilla-plugins/flashplayer/standalone.nix (config.flashplayer or {}); + + flashplayer-standalone-debugger = flashplayer-standalone.override { + debug = true; + }; + + fluxbox = callPackage ../applications/window-managers/fluxbox { }; + + fme = callPackage ../applications/misc/fme { + inherit (gnome2) libglademm; + }; + + fomp = callPackage ../applications/audio/fomp { }; + + fractal = callPackage ../applications/networking/instant-messengers/fractal { }; + + freecad = qt5.callPackage ../applications/graphics/freecad { mpi = openmpi; }; + + freemind = callPackage ../applications/misc/freemind { }; + + freenet = callPackage ../applications/networking/p2p/freenet { }; + + freepv = callPackage ../applications/graphics/freepv { }; + + xfontsel = callPackage ../applications/misc/xfontsel { }; + inherit (xorg) xlsfonts; + + xrdp = callPackage ../applications/networking/remote/xrdp { }; + + freerdp = callPackage ../applications/networking/remote/freerdp { + inherit libpulseaudio; + inherit (gst_all_1) gstreamer gst-plugins-base gst-plugins-good; + }; + + freerdpUnstable = freerdp; + + fte = callPackage ../applications/editors/fte { }; + + game-music-emu = callPackage ../applications/audio/game-music-emu { }; + + gcalcli = callPackage ../applications/misc/gcalcli { }; + + vcal = callPackage ../applications/misc/vcal { }; + + gcolor2 = callPackage ../applications/graphics/gcolor2 { }; + + gcolor3 = callPackage ../applications/graphics/gcolor3 { }; + + get_iplayer = callPackage ../applications/misc/get_iplayer {}; + + getxbook = callPackage ../applications/misc/getxbook { }; + + ghq = gitAndTools.ghq; + + gimp = callPackage ../applications/graphics/gimp { + gegl = gegl_0_4; + lcms = lcms2; + inherit (darwin.apple_sdk.frameworks) AppKit Cocoa; + }; + + gimp-with-plugins = callPackage ../applications/graphics/gimp/wrapper.nix { + plugins = null; # All packaged plugins enabled, if not explicit plugin list supplied + }; + + gimpPlugins = recurseIntoAttrs (callPackage ../applications/graphics/gimp/plugins {}); + + girara = callPackage ../applications/misc/girara { + gtk = gtk3; + }; + + gitAndTools = recurseIntoAttrs (callPackage ../applications/version-management/git-and-tools {}); + + inherit (gitAndTools) git gitFull gitSVN git-cola svn2git git-radar git-secret git-secrets transcrypt git-crypt; + + gitMinimal = git.override { + withManual = false; + pythonSupport = false; + withpcre2 = false; + }; + + gitRepo = callPackage ../applications/version-management/git-repo { + python = python27; + }; + + git-quick-stats = callPackage ../development/tools/git-quick-stats {}; + + git-review = callPackage ../applications/version-management/git-review { }; + + gitolite = callPackage ../applications/version-management/gitolite { }; + + inherit (gnome3) gitg; + + giv = callPackage ../applications/graphics/giv { }; + + gmrun = callPackage ../applications/misc/gmrun {}; + + gnucash = callPackage ../applications/office/gnucash { + inherit (gnome3) dconf; + }; + + goffice = callPackage ../development/libraries/goffice { }; + + jetbrains = (recurseIntoAttrs (callPackages ../applications/editors/jetbrains { + jdk = jetbrains.jdk; + }) // { + jdk = callPackage ../development/compilers/jetbrains-jdk { }; + }); + + libquvi = callPackage ../applications/video/quvi/library.nix { }; + + linssid = libsForQt5.callPackage ../applications/networking/linssid { }; + + lollypop = callPackage ../applications/audio/lollypop { }; + + m32edit = callPackage ../applications/audio/midas/m32edit.nix {}; + + manuskript = callPackage ../applications/editors/manuskript { }; + + manul = callPackage ../development/tools/manul { }; + + mindforger = libsForQt5.callPackage ../applications/editors/mindforger { }; + + mi2ly = callPackage ../applications/audio/mi2ly {}; + + moe = callPackage ../applications/editors/moe { }; + + multibootusb = callPackage ../applications/misc/multibootusb {}; + + praat = callPackage ../applications/audio/praat { }; + + quvi = callPackage ../applications/video/quvi/tool.nix { + lua5_sockets = lua51Packages.luasocket; + lua5 = lua5_1; + }; + + quvi_scripts = callPackage ../applications/video/quvi/scripts.nix { }; + + rhvoice = callPackage ../applications/audio/rhvoice { }; + + svox = callPackage ../applications/audio/svox { }; + + gkrellm = callPackage ../applications/misc/gkrellm { + inherit (darwin) IOKit; + }; + + glowing-bear = callPackage ../applications/networking/irc/glowing-bear { }; + + gmtk = callPackage ../development/libraries/gmtk { }; + + gmu = callPackage ../applications/audio/gmu { }; + + gnome_mplayer = callPackage ../applications/video/gnome-mplayer { }; + + gnumeric = callPackage ../applications/office/gnumeric { }; + + gnunet = callPackage ../applications/networking/p2p/gnunet { }; + + gnunet_git = lowPrio (callPackage ../applications/networking/p2p/gnunet/git.nix { }); + + gocr = callPackage ../applications/graphics/gocr { }; + + gobby5 = callPackage ../applications/editors/gobby { }; + + gphoto2 = callPackage ../applications/misc/gphoto2 { }; + + gphoto2fs = callPackage ../applications/misc/gphoto2/gphotofs.nix { }; + + gramps = callPackage ../applications/misc/gramps { + pythonPackages = python3Packages; + }; + + graphicsmagick = callPackage ../applications/graphics/graphicsmagick { }; + graphicsmagick_q16 = graphicsmagick.override { quantumdepth = 16; }; + + graphicsmagick-imagemagick-compat = callPackage ../applications/graphics/graphicsmagick/compat.nix { }; + + grisbi = callPackage ../applications/office/grisbi { gtk = gtk3; }; + + gtkpod = callPackage ../applications/audio/gtkpod { }; + + jbidwatcher = callPackage ../applications/misc/jbidwatcher { + java = if stdenv.isLinux then jre else jdk; + }; + + qrencode = callPackage ../development/libraries/qrencode { }; + + geeqie = callPackage ../applications/graphics/geeqie { }; + + gigedit = callPackage ../applications/audio/gigedit { }; + + gqview = callPackage ../applications/graphics/gqview { }; + + gmpc = callPackage ../applications/audio/gmpc {}; + + gmtp = callPackage ../applications/misc/gmtp {}; + + gnomecast = callPackage ../applications/video/gnomecast { }; + + celluloid = callPackage ../applications/video/celluloid { }; + + gnome-recipes = callPackage ../applications/misc/gnome-recipes { + inherit (gnome3) gnome-autoar; + }; + + gollum = callPackage ../applications/misc/gollum { }; + + googleearth = callPackage ../applications/misc/googleearth { }; + + google-chrome = callPackage ../applications/networking/browsers/google-chrome { gconf = gnome2.GConf; }; + + google-chrome-beta = google-chrome.override { chromium = chromiumBeta; channel = "beta"; }; + + google-chrome-dev = google-chrome.override { chromium = chromiumDev; channel = "dev"; }; + + google-play-music-desktop-player = callPackage ../applications/audio/google-play-music-desktop-player { + inherit (gnome2) GConf; + }; + + google_talk_plugin = callPackage ../applications/networking/browsers/mozilla-plugins/google-talk-plugin { + libpng = libpng12; + }; + + gosmore = callPackage ../applications/misc/gosmore { }; + + gpsbabel = libsForQt5.callPackage ../applications/misc/gpsbabel { + inherit (darwin) IOKit; + }; + + gpscorrelate = callPackage ../applications/misc/gpscorrelate { }; + + gpsd = callPackage ../servers/gpsd { }; + + gpsprune = callPackage ../applications/misc/gpsprune { }; + + gpxsee = libsForQt5.callPackage ../applications/misc/gpxsee { }; + + gspell = callPackage ../development/libraries/gspell { }; + + gtk2fontsel = callPackage ../applications/misc/gtk2fontsel { }; + + guake = callPackage ../applications/misc/guake { }; + + guardian-agent = callPackage ../tools/networking/guardian-agent { }; + + guitone = callPackage ../applications/version-management/guitone { + graphviz = graphviz_2_32; + }; + + gv = callPackage ../applications/misc/gv { }; + + guvcview = callPackage ../os-specific/linux/guvcview { }; + + gxmessage = callPackage ../applications/misc/gxmessage { }; + + gxplugins-lv2 = callPackage ../applications/audio/gxplugins-lv2 { }; + + hackrf = callPackage ../applications/radio/hackrf { }; + + hakuneko = callPackage ../tools/misc/hakuneko { }; + + hamster-time-tracker = callPackage ../applications/misc/hamster-time-tracker { + inherit (gnome2) gnome_python; + }; + + hashit = callPackage ../tools/misc/hashit { }; + + hello = callPackage ../applications/misc/hello { }; + hello-unfree = callPackage ../applications/misc/hello-unfree { }; + + helmholtz = callPackage ../applications/audio/pd-plugins/helmholtz { }; + + heme = callPackage ../applications/editors/heme { }; + + herbstluftwm = callPackage ../applications/window-managers/herbstluftwm { }; + + hexchat = callPackage ../applications/networking/irc/hexchat { }; + + hexcurse = callPackage ../applications/editors/hexcurse { }; + + hexedit = callPackage ../applications/editors/hexedit { }; + + hipchat = callPackage ../applications/networking/instant-messengers/hipchat { }; + + hledger = haskell.lib.justStaticExecutables haskellPackages.hledger; + hledger-iadd = haskell.lib.justStaticExecutables haskellPackages.hledger-iadd; + hledger-interest = haskell.lib.justStaticExecutables haskellPackages.hledger-interest; + hledger-ui = haskell.lib.justStaticExecutables haskellPackages.hledger-ui; + hledger-web = haskell.lib.justStaticExecutables haskellPackages.hledger-web; + + homebank = callPackage ../applications/office/homebank { + gtk = gtk3; + }; + + hovercraft = python3Packages.callPackage ../applications/misc/hovercraft { }; + + howl = callPackage ../applications/editors/howl { }; + + hpl = callPackage ../tools/misc/hpl { mpi = openmpi; }; + + ht = callPackage ../applications/editors/ht { }; + + hubstaff = callPackage ../applications/misc/hubstaff { }; + + hue-cli = callPackage ../tools/networking/hue-cli { }; + + inherit (nodePackages) hueadm; + + hugin = callPackage ../applications/graphics/hugin { + wxGTK = wxGTK30; + }; + + hugo = callPackage ../applications/misc/hugo { }; + + hydrogen = callPackage ../applications/audio/hydrogen { }; + + hyper = callPackage ../applications/misc/hyper { }; + + hyper-haskell-server-with-packages = callPackage ../development/tools/haskell/hyper-haskell/server.nix { + inherit (haskellPackages) ghcWithPackages; + packages = self: with self; []; + }; + + hyper-haskell = callPackage ../development/tools/haskell/hyper-haskell { + hyper-haskell-server = hyper-haskell-server-with-packages.override { + packages = self: with self; [ + hyper-extra diagrams csound-catalog + ]; + }; + extra-packages = [ csound ]; + }; + + hyperledger-fabric = callPackage ../tools/misc/hyperledger-fabric { }; + + jackline = callPackage ../applications/networking/instant-messengers/jackline { }; + + leftwm = callPackage ../applications/window-managers/leftwm { }; + + pinboard-notes-backup = haskell.lib.overrideCabal + (haskell.lib.generateOptparseApplicativeCompletion "pnbackup" + haskellPackages.pinboard-notes-backup) + (drv: { + postInstall = '' + install -D man/pnbackup.1 $out/share/man/man1/pnbackup.1 + '' + (drv.postInstall or ""); + }); + + slack = callPackage ../applications/networking/instant-messengers/slack { }; + slack-theme-black = callPackage ../applications/networking/instant-messengers/slack/dark-theme.nix { }; + slack-dark = pkgs.slack.override { theme = slack-theme-black; }; + + slack-cli = callPackage ../tools/networking/slack-cli { }; + + slack-term = callPackage ../applications/networking/instant-messengers/slack-term { }; + + singularity = callPackage ../applications/virtualization/singularity { }; + + spectmorph = callPackage ../applications/audio/spectmorph { }; + + spectrwm = callPackage ../applications/window-managers/spectrwm { }; + + spectral = qt5.callPackage ../applications/networking/instant-messengers/spectral { }; + + spotifyd = callPackage ../applications/audio/spotifyd { + withALSA = stdenv.isLinux; + withPulseAudio = config.pulseaudio or true; + withPortAudio = stdenv.isDarwin; + }; + + super-productivity = callPackage ../applications/networking/super-productivity { }; + + wlroots = callPackage ../development/libraries/wlroots { }; + + sway = callPackage ../applications/window-managers/sway { }; + swaybg = callPackage ../applications/window-managers/sway/bg.nix { }; + swayidle = callPackage ../applications/window-managers/sway/idle.nix { }; + swaylock = callPackage ../applications/window-managers/sway/lock.nix { }; + + waybar = callPackage ../applications/misc/waybar { + pulseSupport = config.pulseaudio or false; + }; + + i3 = callPackage ../applications/window-managers/i3 { + xcb-util-cursor = if stdenv.isDarwin then xcb-util-cursor-HEAD else xcb-util-cursor; + }; + + i3-gaps = callPackage ../applications/window-managers/i3/gaps.nix { }; + + i3-easyfocus = callPackage ../applications/window-managers/i3/easyfocus.nix { }; + + i3-layout-manager = callPackage ../applications/window-managers/i3/layout-manager.nix { }; + + i3blocks = callPackage ../applications/window-managers/i3/blocks.nix { }; + + i3blocks-gaps = callPackage ../applications/window-managers/i3/blocks-gaps.nix { }; + + i3cat = callPackage ../tools/misc/i3cat { }; + + i3ipc-glib = callPackage ../applications/window-managers/i3/i3ipc-glib.nix { }; + + i3lock = callPackage ../applications/window-managers/i3/lock.nix { + cairo = cairo.override { xcbSupport = true; }; + }; + + i3lock-color = callPackage ../applications/window-managers/i3/lock-color.nix { }; + + i3lock-fancy = callPackage ../applications/window-managers/i3/lock-fancy.nix { }; + + i3lock-pixeled = callPackage ../misc/screensavers/i3lock-pixeled { }; + + betterlockscreen = callPackage ../misc/screensavers/betterlockscreen { + inherit (xorg) xrdb; + }; + + i3minator = callPackage ../tools/misc/i3minator { }; + + i3pystatus = callPackage ../applications/window-managers/i3/pystatus.nix { }; + + i3status = callPackage ../applications/window-managers/i3/status.nix { }; + + i3status-rust = callPackage ../applications/window-managers/i3/status-rust.nix { }; + + i3-wk-switch = callPackage ../applications/window-managers/i3/wk-switch.nix { }; + + wmfocus = callPackage ../applications/window-managers/i3/wmfocus.nix { }; + + wmfs = callPackage ../applications/window-managers/wmfs/default.nix { }; + + i810switch = callPackage ../os-specific/linux/i810switch { }; + + icewm = callPackage ../applications/window-managers/icewm {}; + + id3v2 = callPackage ../applications/audio/id3v2 { }; + + ifenslave = callPackage ../os-specific/linux/ifenslave { }; + + ii = callPackage ../applications/networking/irc/ii { + stdenv = gccStdenv; + }; + + ike = callPackage ../applications/networking/ike { }; + + ikiwiki = callPackage ../applications/misc/ikiwiki { + inherit (perlPackages.override { pkgs = pkgs // { imagemagick = imagemagickBig;}; }) PerlMagick; + }; + + iksemel = callPackage ../development/libraries/iksemel { }; + + imagej = callPackage ../applications/graphics/imagej { }; + + imagemagick_light = imagemagick.override { + bzip2 = null; + zlib = null; + libX11 = null; + libXext = null; + libXt = null; + fontconfig = null; + freetype = null; + ghostscript = null; + libjpeg = null; + djvulibre = null; + lcms2 = null; + openexr = null; + libpng = null; + librsvg = null; + libtiff = null; + libxml2 = null; + openjpeg = null; + libwebp = null; + libheif = null; + libde265 = null; + }; + + imagemagick = callPackage ../applications/graphics/ImageMagick { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + ghostscript = null; + }; + + imagemagickBig = imagemagick.override { inherit ghostscript; }; + + imagemagick7_light = lowPrio (imagemagick7.override { + bzip2 = null; + zlib = null; + libX11 = null; + libXext = null; + libXt = null; + fontconfig = null; + freetype = null; + ghostscript = null; + libjpeg = null; + djvulibre = null; + lcms2 = null; + openexr = null; + libpng = null; + librsvg = null; + libtiff = null; + libxml2 = null; + openjpeg = null; + libwebp = null; + libheif = null; + }); + + imagemagick7 = lowPrio (imagemagick7Big.override { + ghostscript = null; + }); + + imagemagick7Big = lowPrio (callPackage ../applications/graphics/ImageMagick/7.0.nix { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + }); + + inherit (nodePackages) imapnotify; + + img2pdf = callPackage ../applications/misc/img2pdf { }; + + imgcat = callPackage ../applications/graphics/imgcat { }; + + # Impressive, formerly known as "KeyJNote". + impressive = callPackage ../applications/office/impressive { }; + + inkscape = callPackage ../applications/graphics/inkscape { + lcms = lcms2; + poppler = poppler_0_61; + }; + + inspectrum = libsForQt5.callPackage ../applications/radio/inspectrum { }; + + ion3 = callPackage ../applications/window-managers/ion-3 { + lua = lua5_1; + }; + + ipe = libsForQt5.callPackage ../applications/graphics/ipe { + ghostscript = ghostscriptX; + texlive = texlive.combine { inherit (texlive) scheme-small; }; + lua5 = lua5_3; + }; + + iptraf = callPackage ../applications/networking/iptraf { }; + + iptraf-ng = callPackage ../applications/networking/iptraf-ng { }; + + irccloud = callPackage ../applications/networking/irc/irccloud { }; + + irssi = callPackage ../applications/networking/irc/irssi { }; + + irssi_fish = callPackage ../applications/networking/irc/irssi/fish { }; + + ir.lv2 = callPackage ../applications/audio/ir.lv2 { }; + + bip = callPackage ../applications/networking/irc/bip { }; + + j4-dmenu-desktop = callPackage ../applications/misc/j4-dmenu-desktop { }; + + jabref = callPackage ../applications/office/jabref { }; + + jack_capture = callPackage ../applications/audio/jack-capture { }; + + jack_oscrolloscope = callPackage ../applications/audio/jack-oscrolloscope { }; + + jack_rack = callPackage ../applications/audio/jack-rack { }; + + jackmeter = callPackage ../applications/audio/jackmeter { }; + + jackmix = callPackage ../applications/audio/jackmix { }; + jackmix_jack1 = jackmix.override { jack = jack1; }; + + jalv = callPackage ../applications/audio/jalv { }; + + jameica = callPackage ../applications/office/jameica { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + + jamin = callPackage ../applications/audio/jamin { }; + + japa = callPackage ../applications/audio/japa { }; + + jdupes = callPackage ../tools/misc/jdupes { }; + + jedit = callPackage ../applications/editors/jedit { }; + + jgmenu = callPackage ../applications/misc/jgmenu { }; + + jigdo = callPackage ../applications/misc/jigdo { }; + + jitsi = callPackage ../applications/networking/instant-messengers/jitsi { }; + + joe = callPackage ../applications/editors/joe { }; + + josm = callPackage ../applications/misc/josm { }; + + jormungandr = callPackage ../applications/altcoins/jormungandr { }; + + jbrout = callPackage ../applications/graphics/jbrout { }; + + jwm = callPackage ../applications/window-managers/jwm { }; + + jwm-settings-manager = callPackage ../applications/window-managers/jwm/jwm-settings-manager.nix { }; + + k3d = callPackage ../applications/graphics/k3d { + inherit (pkgs.gnome2) gtkglext; + stdenv = gcc6Stdenv; + boost = boost166.override { enablePython = true; }; + }; + + k9copy = libsForQt5.callPackage ../applications/video/k9copy {}; + + kail = callPackage ../tools/networking/kail { }; + + kanboard = callPackage ../applications/misc/kanboard { }; + + kanshi = callPackage ../tools/misc/kanshi { }; + + kdeApplications = + let + mkApplications = import ../applications/kde; + attrs = { + inherit lib libsForQt5 fetchurl; + inherit okteta; + }; + in + recurseIntoAttrs (makeOverridable mkApplications attrs); + + inherit (kdeApplications) + akonadi akregator ark dolphin dragon ffmpegthumbs filelight gwenview k3b + kaddressbook kate kcachegrind kcalc kcharselect kcolorchooser kcontacts kdenlive kdf kdialog + keditbookmarks kfind kget kgpg khelpcenter kig kleopatra kmail kmix kmplot kolourpaint kompare konsole + kpkpass kitinerary kontact korganizer krdc krfb ksystemlog ktouch kwalletmanager marble minuet okular spectacle; + + okteta = libsForQt5.callPackage ../applications/editors/okteta { }; + + kdeconnect = libsForQt5.callPackage ../applications/misc/kdeconnect { }; + + kdecoration-viewer = libsForQt5.callPackage ../tools/misc/kdecoration-viewer { }; + + inherit (kdeFrameworks) kdesu; + + kdevelop-pg-qt = libsForQt5.callPackage ../applications/editors/kdevelop5/kdevelop-pg-qt.nix { }; + + kdevelop-unwrapped = libsForQt5.callPackage ../applications/editors/kdevelop5/kdevelop.nix { + llvmPackages = llvmPackages_7; + }; + + kdev-php = libsForQt5.callPackage ../applications/editors/kdevelop5/kdev-php.nix { }; + kdev-python = libsForQt5.callPackage ../applications/editors/kdevelop5/kdev-python.nix { + python = python3; + }; + + kdevelop = libsForQt5.callPackage ../applications/editors/kdevelop5/wrapper.nix { }; + + keepnote = callPackage ../applications/office/keepnote { }; + + kega-fusion = pkgsi686Linux.callPackage ../misc/emulators/kega-fusion { }; + + kermit = callPackage ../tools/misc/kermit { }; + + kexi = libsForQt5.callPackage ../applications/office/kexi { }; + + keyfinder = libsForQt5.callPackage ../applications/audio/keyfinder { }; + + keyfinder-cli = libsForQt5.callPackage ../applications/audio/keyfinder-cli { }; + + keymon = callPackage ../applications/video/key-mon { }; + + kgraphviewer = libsForQt5.callPackage ../applications/graphics/kgraphviewer { }; + + khal = callPackage ../applications/misc/khal { }; + + khard = callPackage ../applications/misc/khard { }; + + kid3 = libsForQt5.callPackage ../applications/audio/kid3 { }; + + kile = libsForQt5.callPackage ../applications/editors/kile { }; + + kino = callPackage ../applications/video/kino { + inherit (gnome2) libglade; + ffmpeg = ffmpeg_2; + }; + + kipi-plugins = libsForQt5.callPackage ../applications/graphics/kipi-plugins { }; + + kitty = callPackage ../applications/misc/kitty { + harfbuzz = harfbuzz.override { withCoreText = stdenv.isDarwin; }; + inherit (darwin.apple_sdk.frameworks) Cocoa CoreGraphics Foundation IOKit Kernel OpenGL; + }; + + kiwix = callPackage ../applications/misc/kiwix { }; + + kmplayer = libsForQt5.callPackage ../applications/video/kmplayer { }; + + kmymoney = libsForQt5.callPackage ../applications/office/kmymoney { + inherit (kdeApplications) kidentitymanagement; + inherit (kdeFrameworks) kdewebkit; + }; + + kodestudio = callPackage ../applications/editors/kodestudio { }; + + konversation = libsForQt5.callPackage ../applications/networking/irc/konversation { }; + + krita = libsForQt5.callPackage ../applications/graphics/krita { + openjpeg = openjpeg_1; + }; + + krusader = libsForQt5.callPackage ../applications/misc/krusader { }; + + ksuperkey = callPackage ../tools/X11/ksuperkey { }; + + ktorrent = libsForQt5.callPackage ../applications/networking/p2p/ktorrent { }; + + kubecfg = callPackage ../applications/networking/cluster/kubecfg { }; + + kubeval = callPackage ../applications/networking/cluster/kubeval { }; + + kubernetes = callPackage ../applications/networking/cluster/kubernetes { }; + + kubectl = callPackage ../applications/networking/cluster/kubectl { }; + + kubeless = callPackage ../applications/networking/cluster/kubeless { }; + + k9s = callPackage ../applications/networking/cluster/k9s { }; + + fluxctl = callPackage ../applications/networking/cluster/fluxctl { }; + + linkerd = callPackage ../applications/networking/cluster/linkerd { }; + + kubernetes-helm = callPackage ../applications/networking/cluster/helm { }; + + kubetail = callPackage ../applications/networking/cluster/kubetail { } ; + + kupfer = callPackage ../applications/misc/kupfer { + # using python36 as there appears to be a waf issue with python37 + # see https://github.com/NixOS/nixpkgs/issues/60498 + python3Packages = python36Packages; + }; + + kvirc = libsForQt5.callPackage ../applications/networking/irc/kvirc { }; + + lame = callPackage ../development/libraries/lame { }; + + larswm = callPackage ../applications/window-managers/larswm { }; + + lash = callPackage ../applications/audio/lash { }; + + ladspaH = callPackage ../applications/audio/ladspa-sdk/ladspah.nix { }; + + ladspaPlugins = callPackage ../applications/audio/ladspa-plugins { + fftw = fftwSinglePrec; + }; + + ladspa-sdk = callPackage ../applications/audio/ladspa-sdk { }; + + caps = callPackage ../applications/audio/caps { }; + + lastfmsubmitd = callPackage ../applications/audio/lastfmsubmitd { }; + + lbdb = callPackage ../tools/misc/lbdb { abook = null; gnupg = null; goobook = null; khard = null; mu = null; }; + + lbzip2 = callPackage ../tools/compression/lbzip2 { }; + + lci = callPackage ../applications/science/logic/lci {}; + + lemonbar = callPackage ../applications/window-managers/lemonbar { }; + + lemonbar-xft = callPackage ../applications/window-managers/lemonbar/xft.nix { }; + + leo-editor = callPackage ../applications/editors/leo-editor { }; + + libowfat = callPackage ../development/libraries/libowfat { }; + + librecad = callPackage ../applications/misc/librecad { }; + + libreoffice = hiPrio libreoffice-still; + libreoffice-unwrapped = libreoffice.libreoffice; + + libreoffice-args = { + inherit (perlPackages) ArchiveZip IOCompress; + inherit (gnome2) GConf ORBit2 gnome_vfs; + zip = zip.override { enableNLS = false; }; + fontsConf = makeFontsConf { + fontDirectories = [ + carlito dejavu_fonts + freefont_ttf xorg.fontmiscmisc + liberation_ttf_v1 + liberation_ttf_v2 + ]; + }; + clucene_core = clucene_core_2; + lcms = lcms2; + harfbuzz = harfbuzz.override { + withIcu = true; withGraphite2 = true; + }; + }; + + libreoffice-fresh = lowPrio (callPackage ../applications/office/libreoffice/wrapper.nix { + libreoffice = callPackage ../applications/office/libreoffice + (libreoffice-args // { + }); + }); + libreoffice-fresh-unwrapped = libreoffice-fresh.libreoffice; + + libreoffice-still = lowPrio (callPackage ../applications/office/libreoffice/wrapper.nix { + libreoffice = callPackage ../applications/office/libreoffice/still.nix + (libreoffice-args // { + }); + }); + libreoffice-still-unwrapped = libreoffice-still.libreoffice; + + libvmi = callPackage ../development/libraries/libvmi { }; + + lifelines = callPackage ../applications/misc/lifelines { }; + + liferea = callPackage ../applications/networking/newsreaders/liferea { + inherit (gnome3) dconf; + }; + + lightworks = callPackage ../applications/video/lightworks { + portaudio = portaudio2014; + }; + + lingot = callPackage ../applications/audio/lingot { + inherit (gnome2) libglade; + }; + + linuxband = callPackage ../applications/audio/linuxband { }; + + ledger2 = callPackage ../applications/office/ledger/2.6.3.nix { }; + ledger3 = callPackage ../applications/office/ledger { + boost = boost15x; + }; + ledger = ledger3; + + ledger-autosync = callPackage ../applications/office/ledger-autosync { }; + + ledger-web = callPackage ../applications/office/ledger-web { }; + + lighthouse = callPackage ../applications/misc/lighthouse { }; + + lighttable = callPackage ../applications/editors/lighttable {}; + + libdsk = callPackage ../misc/emulators/libdsk { }; + + links2 = callPackage ../applications/networking/browsers/links2 { }; + + linphone = callPackage ../applications/networking/instant-messengers/linphone rec { + polarssl = mbedtls_1_3; + }; + + linuxsampler = callPackage ../applications/audio/linuxsampler { }; + + llpp = ocaml-ng.ocamlPackages_4_07.callPackage ../applications/misc/llpp { }; + + lmms = libsForQt5.callPackage ../applications/audio/lmms { + lame = null; + libsoundio = null; + portaudio = null; + }; + + loxodo = callPackage ../applications/misc/loxodo { }; + + lrzsz = callPackage ../tools/misc/lrzsz { }; + + lsp-plugins = callPackage ../applications/audio/lsp-plugins { }; + + luminanceHDR = libsForQt5.callPackage ../applications/graphics/luminance-hdr { }; + + lxdvdrip = callPackage ../applications/video/lxdvdrip { }; + + handbrake = callPackage ../applications/video/handbrake { }; + + lilyterm = callPackage ../applications/misc/lilyterm { + inherit (gnome2) vte; + gtk = gtk2; + flavour = "stable"; + }; + + lilyterm-git = lilyterm.override { + flavour = "git"; + }; + + luakit = callPackage ../applications/networking/browsers/luakit { + inherit (luajitPackages) luafilesystem; + }; + + looking-glass-client = callPackage ../applications/virtualization/looking-glass-client { }; + + ltc-tools = callPackage ../applications/audio/ltc-tools { }; + + lumail = callPackage ../applications/networking/mailreaders/lumail { + lua = lua5_1; + }; + + luppp = callPackage ../applications/audio/luppp { }; + + lutris-unwrapped = python3.pkgs.callPackage ../applications/misc/lutris { + inherit (gnome3) gnome-desktop libgnome-keyring webkitgtk; + wine = wineWowPackages.staging; + }; + lutris = callPackage ../applications/misc/lutris/chrootenv.nix { }; + lutris-free = lutris.override { + steamSupport = false; + }; + + lv2bm = callPackage ../applications/audio/lv2bm { }; + + lynx = callPackage ../applications/networking/browsers/lynx { }; + + lyx = libsForQt5.callPackage ../applications/misc/lyx { }; + + mac = callPackage ../development/libraries/mac { }; + + macdylibbundler = callPackage ../development/tools/misc/macdylibbundler { }; + + magic-wormhole = with python3Packages; toPythonApplication magic-wormhole; + + mail-notification = callPackage ../desktops/gnome-2/desktop/mail-notification {}; + + magnetophonDSP = { + CharacterCompressor = callPackage ../applications/audio/magnetophonDSP/CharacterCompressor { }; + CompBus = callPackage ../applications/audio/magnetophonDSP/CompBus { }; + ConstantDetuneChorus = callPackage ../applications/audio/magnetophonDSP/ConstantDetuneChorus { }; + faustCompressors = callPackage ../applications/audio/magnetophonDSP/faustCompressors { }; + LazyLimiter = callPackage ../applications/audio/magnetophonDSP/LazyLimiter { }; + MBdistortion = callPackage ../applications/audio/magnetophonDSP/MBdistortion { }; + pluginUtils = callPackage ../applications/audio/magnetophonDSP/pluginUtils { }; + RhythmDelay = callPackage ../applications/audio/magnetophonDSP/RhythmDelay { }; + VoiceOfFaust = callPackage ../applications/audio/magnetophonDSP/VoiceOfFaust { }; + shelfMultiBand = callPackage ../applications/audio/magnetophonDSP/shelfMultiBand { }; + }; + + makeself = callPackage ../applications/misc/makeself { }; + + mako = callPackage ../applications/misc/mako { }; + + mapmap = libsForQt5.callPackage ../applications/video/mapmap { }; + + marathon = callPackage ../applications/networking/cluster/marathon { }; + marathonctl = callPackage ../tools/virtualization/marathonctl { } ; + + markdown-pp = callPackage ../tools/text/markdown-pp { }; + + marp = callPackage ../applications/office/marp { }; + + matchbox = callPackage ../applications/window-managers/matchbox { }; + + mblaze = callPackage ../applications/networking/mailreaders/mblaze { }; + + mcpp = callPackage ../development/compilers/mcpp { }; + + mda_lv2 = callPackage ../applications/audio/mda-lv2 { }; + + mediainfo = callPackage ../applications/misc/mediainfo { }; + + mediainfo-gui = callPackage ../applications/misc/mediainfo-gui { }; + + # mediathekview needs JavaFX, which currently only is available inside OracleJRE + # we might be able to get rid of it, as soon as we have an OpenJRE with OpenJFX included + mediathekview = callPackage ../applications/video/mediathekview { jre = oraclejre; }; + + meteo = callPackage ../applications/networking/weather/meteo { }; + + meld = callPackage ../applications/version-management/meld { }; + + meme = callPackage ../applications/graphics/meme { }; + + mcomix = callPackage ../applications/graphics/mcomix { }; + + mendeley = libsForQt5.callPackage ../applications/office/mendeley { + gconf = pkgs.gnome2.GConf; + }; + + menumaker = callPackage ../applications/misc/menumaker { }; + + mercurial = callPackage ../applications/version-management/mercurial { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + }; + + mercurialFull = appendToName "full" (pkgs.mercurial.override { guiSupport = true; }); + + merkaartor = libsForQt59.callPackage ../applications/misc/merkaartor { + gdal = gdal_2; # https://github.com/openstreetmap/merkaartor/issues/179 + }; + + meshlab = libsForQt5.callPackage ../applications/graphics/meshlab { }; + + metersLv2 = callPackage ../applications/audio/meters_lv2 { }; + + mhwaveedit = callPackage ../applications/audio/mhwaveedit {}; + + mid2key = callPackage ../applications/audio/mid2key { }; + + midori-unwrapped = callPackage ../applications/networking/browsers/midori { }; + midori = wrapFirefox midori-unwrapped { }; + + mikmod = callPackage ../applications/audio/mikmod { }; + + minicom = callPackage ../tools/misc/minicom { }; + + minimodem = callPackage ../applications/radio/minimodem { }; + + minidjvu = callPackage ../applications/graphics/minidjvu { }; + + minikube = callPackage ../applications/networking/cluster/minikube { + inherit (darwin.apple_sdk.frameworks) vmnet; + }; + + minishift = callPackage ../applications/networking/cluster/minishift { }; + + minitube = libsForQt5.callPackage ../applications/video/minitube { }; + + mimic = callPackage ../applications/audio/mimic { }; + + mimms = callPackage ../applications/audio/mimms {}; + + meh = callPackage ../applications/graphics/meh {}; + + mirage = callPackage ../applications/graphics/mirage { }; + + mixxx = libsForQt5.callPackage ../applications/audio/mixxx { + inherit (vamp) vampSDK; + }; + + mjpg-streamer = callPackage ../applications/video/mjpg-streamer { }; + + mldonkey = callPackage ../applications/networking/p2p/mldonkey { + ocamlPackages = ocaml-ng.ocamlPackages_4_05; + }; + + MMA = callPackage ../applications/audio/MMA { }; + + mmex = callPackage ../applications/office/mmex { + wxGTK30 = wxGTK30.override { withWebKit = true ; }; + }; + + moc = callPackage ../applications/audio/moc { }; + + mod-distortion = callPackage ../applications/audio/mod-distortion { }; + + monero = callPackage ../applications/altcoins/monero { + inherit (darwin.apple_sdk.frameworks) CoreData IOKit PCSC; + }; + + monero-gui = libsForQt5.callPackage ../applications/altcoins/monero-gui { + boost = boost16x; + }; + + xmr-stak = callPackage ../applications/misc/xmr-stak { + stdenvGcc6 = gcc6Stdenv; + }; + + xmrig = callPackage ../applications/misc/xmrig { }; + + xmrig-proxy = callPackage ../applications/misc/xmrig/proxy.nix { }; + + monkeysAudio = callPackage ../applications/audio/monkeys-audio { }; + + monkeysphere = callPackage ../tools/security/monkeysphere { }; + + monodevelop = callPackage ../applications/editors/monodevelop {}; + + monotone = callPackage ../applications/version-management/monotone { + lua = lua5; + }; + + inherit (ocaml-ng.ocamlPackages_4_01_0) monotoneViz; + + moolticute = libsForQt5.callPackage ../applications/misc/moolticute { }; + + moonlight-embedded = callPackage ../applications/misc/moonlight-embedded { }; + + mop = callPackage ../applications/misc/mop { }; + + mopidy = callPackage ../applications/audio/mopidy { }; + + mopidy-gmusic = callPackage ../applications/audio/mopidy/gmusic.nix { }; + + mopidy-local-images = callPackage ../applications/audio/mopidy/local-images.nix { }; + + mopidy-local-sqlite = callPackage ../applications/audio/mopidy/local-sqlite.nix { }; + + mopidy-spotify = callPackage ../applications/audio/mopidy/spotify.nix { }; + + mopidy-moped = callPackage ../applications/audio/mopidy/moped.nix { }; + + mopidy-mopify = callPackage ../applications/audio/mopidy/mopify.nix { }; + + mopidy-spotify-tunigo = callPackage ../applications/audio/mopidy/spotify-tunigo.nix { }; + + mopidy-youtube = callPackage ../applications/audio/mopidy/youtube.nix { }; + + mopidy-soundcloud = callPackage ../applications/audio/mopidy/soundcloud.nix { }; + + mopidy-musicbox-webclient = callPackage ../applications/audio/mopidy/musicbox-webclient.nix { }; + + mopidy-iris = callPackage ../applications/audio/mopidy/iris.nix { }; + + motif = callPackage ../development/libraries/motif { }; + + mozplugger = callPackage ../applications/networking/browsers/mozilla-plugins/mozplugger {}; + + mozjpeg = callPackage ../applications/graphics/mozjpeg { }; + + easytag = callPackage ../applications/audio/easytag { }; + + mp3gain = callPackage ../applications/audio/mp3gain { }; + + mp3info = callPackage ../applications/audio/mp3info { }; + + mp3splt = callPackage ../applications/audio/mp3splt { }; + + mp3val = callPackage ../applications/audio/mp3val { }; + + mpc123 = callPackage ../applications/audio/mpc123 { }; + + mpg123 = callPackage ../applications/audio/mpg123 { }; + + mpg321 = callPackage ../applications/audio/mpg321 { }; + + mpc_cli = callPackage ../applications/audio/mpc { }; + + clerk = callPackage ../applications/audio/clerk { }; + + nbstripout = callPackage ../applications/version-management/nbstripout { }; + + ncmpc = callPackage ../applications/audio/ncmpc { }; + + ncmpcpp = callPackage ../applications/audio/ncmpcpp { }; + + ympd = callPackage ../applications/audio/ympd { }; + + nload = callPackage ../applications/networking/nload { }; + + normalize = callPackage ../applications/audio/normalize { }; + + mm = callPackage ../applications/networking/instant-messengers/mm { }; + + mm-common = callPackage ../development/libraries/mm-common { }; + + # Renamed + matrique = spectral; + + mpc-qt = libsForQt5.callPackage ../applications/video/mpc-qt { }; + + mplayer = callPackage ../applications/video/mplayer ({ + libdvdnav = libdvdnav_4_2_1; + } // (config.mplayer or {})); + + MPlayerPlugin = browser: + callPackage ../applications/networking/browsers/mozilla-plugins/mplayerplug-in { + inherit browser; + # !!! should depend on MPlayer + }; + + mpv = callPackage ../applications/video/mpv { + inherit lua; + }; + + mpv-with-scripts = callPackage ../applications/video/mpv/wrapper.nix { }; + + mpvScripts = { + convert = callPackage ../applications/video/mpv/scripts/convert.nix {}; + mpris = callPackage ../applications/video/mpv/scripts/mpris.nix {}; + }; + + mrpeach = callPackage ../applications/audio/pd-plugins/mrpeach { }; + + mrxvt = callPackage ../applications/misc/mrxvt { }; + + mtpaint = callPackage ../applications/graphics/mtpaint { }; + + mucommander = callPackage ../applications/misc/mucommander { }; + + multimarkdown = callPackage ../tools/typesetting/multimarkdown { }; + + multimon-ng = callPackage ../applications/radio/multimon-ng { }; + + inherit (callPackages ../applications/networking/mumble { + avahi = avahi-compat; + jackSupport = config.mumble.jackSupport or false; + speechdSupport = config.mumble.speechdSupport or false; + pulseSupport = config.pulseaudio or false; + iceSupport = config.murmur.iceSupport or true; + }) mumble mumble_rc murmur; + + inherit (callPackages ../applications/networking/mumble { + avahi = avahi-compat; + jackSupport = config.mumble.jackSupport or false; + speechdSupport = config.mumble.speechdSupport or false; + pulseSupport = config.pulseaudio or false; + iceSupport = false; + }) murmur_rc; + + mumble_overlay = callPackage ../applications/networking/mumble/overlay.nix { + mumble_i686 = if stdenv.hostPlatform.system == "x86_64-linux" + then pkgsi686Linux.mumble + else null; + }; + + # TODO: we should probably merge these 2 + musescore = + if stdenv.isDarwin then + callPackage ../applications/audio/musescore/darwin.nix { } + else + libsForQt5.callPackage ../applications/audio/musescore { }; + + mutt = callPackage ../applications/networking/mailreaders/mutt { }; + mutt-with-sidebar = mutt.override { + withSidebar = true; + }; + + mwic = callPackage ../applications/misc/mwic { + pythonPackages = python3Packages; + }; + + neap = callPackage ../applications/misc/neap { }; + + neomutt = callPackage ../applications/networking/mailreaders/neomutt { }; + + natron = callPackage ../applications/video/natron { }; + + neocomp = callPackage ../applications/window-managers/neocomp { }; + + nicotine-plus = callPackage ../applications/networking/soulseek/nicotine-plus { + geoip = geoipWithDatabase; + }; + + notion = callPackage ../applications/window-managers/notion { }; + + openshift = callPackage ../applications/networking/cluster/openshift { }; + + oroborus = callPackage ../applications/window-managers/oroborus {}; + + osm2pgsql = callPackage ../tools/misc/osm2pgsql { }; + + ostinato = callPackage ../applications/networking/ostinato { }; + + p4v = libsForQt5.callPackage ../applications/version-management/p4v { }; + + partio = callPackage ../development/libraries/partio {}; + + pcmanfm = callPackage ../applications/misc/pcmanfm { }; + + pcmanfm-qt = lxqt.pcmanfm-qt; + + pcmanx-gtk2 = callPackage ../applications/misc/pcmanx-gtk2 { }; + + pig = callPackage ../applications/networking/cluster/pig { }; + + pijul = callPackage ../applications/version-management/pijul { + inherit (llvmPackages) clang libclang; + }; + + ping = callPackage ../applications/networking/ping { }; + + piper = callPackage ../os-specific/linux/piper { }; + + plank = callPackage ../applications/misc/plank { }; + + planner = callPackage ../applications/office/planner { }; + + playonlinux = callPackage ../applications/misc/playonlinux { + stdenv = stdenv_32bit; + }; + + polybar = callPackage ../applications/misc/polybar { }; + + polybarFull = callPackage ../applications/misc/polybar { + alsaSupport = true; + githubSupport = true; + mpdSupport = true; + pulseSupport = true; + iwSupport = false; + nlSupport = true; + i3Support = true; + i3GapsSupport = false; + }; + + ptex = callPackage ../development/libraries/ptex {}; + + qtcurve = libsForQt5.callPackage ../misc/themes/qtcurve {}; + + rssguard = libsForQt5.callPackage ../applications/networking/feedreaders/rssguard { }; + + scudcloud = callPackage ../applications/networking/instant-messengers/scudcloud { }; + + shotcut = libsForQt5.callPackage ../applications/video/shotcut { + libmlt = mlt; + }; + + shogun = callPackage ../applications/science/machine-learning/shogun { }; + + sky = callPackage ../applications/networking/instant-messengers/sky {}; + + smplayer = libsForQt5.callPackage ../applications/video/smplayer { }; + + smtube = libsForQt5.callPackage ../applications/video/smtube {}; + + stride = callPackage ../applications/networking/instant-messengers/stride { }; + + sudolikeaboss = callPackage ../tools/security/sudolikeaboss { }; + + speedread = callPackage ../applications/misc/speedread { }; + + sup = callPackage ../applications/networking/mailreaders/sup { + bundlerApp = bundlerApp.override{ + ruby = ruby.override { cursesSupport = true; }; + }; + }; + + synapse = callPackage ../applications/misc/synapse { }; + + synapse-bt = callPackage ../applications/networking/p2p/synapse-bt { + inherit (darwin.apple_sdk.frameworks) CoreServices Security; + }; + + synfigstudio = callPackage ../applications/graphics/synfigstudio { + mlt-qt5 = libsForQt5.mlt; + }; + + typora = callPackage ../applications/editors/typora { }; + + taxi = callPackage ../applications/networking/ftp/taxi { }; + + librep = callPackage ../development/libraries/librep { }; + + rep-gtk = callPackage ../development/libraries/rep-gtk { }; + + sawfish = callPackage ../applications/window-managers/sawfish { }; + + sidplayfp = callPackage ../applications/audio/sidplayfp { }; + + sxhkd = callPackage ../applications/window-managers/sxhkd { }; + + mpop = callPackage ../applications/networking/mpop { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + msmtp = callPackage ../applications/networking/msmtp { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + imapfilter = callPackage ../applications/networking/mailreaders/imapfilter.nix { + lua = lua5; + }; + + maxlib = callPackage ../applications/audio/pd-plugins/maxlib { }; + + maxscale = callPackage ../tools/networking/maxscale { + stdenv = gcc6Stdenv; + }; + + pdfdiff = callPackage ../applications/misc/pdfdiff { }; + + mupdf = callPackage ../applications/misc/mupdf { }; + + mystem = callPackage ../applications/misc/mystem { }; + + diffpdf = libsForQt5.callPackage ../applications/misc/diffpdf { }; + + diff-pdf = callPackage ../applications/misc/diff-pdf { wxGTK = wxGTK31; }; + + mlocate = callPackage ../tools/misc/mlocate { }; + + mypaint = callPackage ../applications/graphics/mypaint { }; + + mypaint-brushes = callPackage ../development/libraries/mypaint-brushes { }; + + mythtv = libsForQt5.callPackage ../applications/video/mythtv { }; + + micro = callPackage ../applications/editors/micro { }; + + nano = callPackage ../applications/editors/nano { }; + + nanoblogger = callPackage ../applications/misc/nanoblogger { }; + + nanorc = callPackage ../applications/editors/nano/nanorc { }; + + navipowm = callPackage ../applications/misc/navipowm { }; + + navit = libsForQt5.callPackage ../applications/misc/navit { }; + + netbeans = callPackage ../applications/editors/netbeans { }; + + ncdu = callPackage ../tools/misc/ncdu { }; + + ncdc = callPackage ../applications/networking/p2p/ncdc { }; + + ncview = callPackage ../tools/X11/ncview { } ; + + ne = callPackage ../applications/editors/ne { }; + + nedit = callPackage ../applications/editors/nedit { }; + + nheko = libsForQt5.callPackage ../applications/networking/instant-messengers/nheko { }; + + nomacs = libsForQt5.callPackage ../applications/graphics/nomacs { }; + + notepadqq = libsForQt5.callPackage ../applications/editors/notepadqq { }; + + notbit = callPackage ../applications/networking/mailreaders/notbit { }; + + notmuch = callPackage ../applications/networking/mailreaders/notmuch { + gmime = gmime3; + pythonPackages = python3Packages; + }; + + notejot = callPackage ../applications/misc/notejot { }; + + notmuch-mutt = callPackage ../applications/networking/mailreaders/notmuch/mutt.nix { }; + + muchsync = callPackage ../applications/networking/mailreaders/notmuch/muchsync.nix { }; + + notmuch-addrlookup = callPackage ../applications/networking/mailreaders/notmuch-addrlookup { }; + + nova-filters = callPackage ../applications/audio/nova-filters { }; + + nspluginwrapper = callPackage ../applications/networking/browsers/mozilla-plugins/nspluginwrapper {}; + + nvi = callPackage ../applications/editors/nvi { }; + + nvpy = callPackage ../applications/editors/nvpy { }; + + obconf = callPackage ../tools/X11/obconf { + inherit (gnome2) libglade; + }; + + oblogout = callPackage ../tools/X11/oblogout { }; + + obs-linuxbrowser = callPackage ../applications/video/obs-studio/linuxbrowser.nix { }; + + obs-studio = libsForQt5.callPackage ../applications/video/obs-studio { }; + + octoprint = callPackage ../applications/misc/octoprint { }; + + octoprint-plugins = callPackage ../applications/misc/octoprint/plugins.nix { }; + + ocrad = callPackage ../applications/graphics/ocrad { }; + + offrss = callPackage ../applications/networking/offrss { }; + + ogmtools = callPackage ../applications/video/ogmtools { }; + + omegat = callPackage ../applications/misc/omegat.nix { }; + + omxplayer = callPackage ../applications/video/omxplayer { }; + + openbox = callPackage ../applications/window-managers/openbox { }; + + openbox-menu = callPackage ../applications/misc/openbox-menu { + stdenv = gccStdenv; + }; + + openbrf = libsForQt5.callPackage ../applications/misc/openbrf { }; + + opencpn = callPackage ../applications/misc/opencpn { }; + + openfx = callPackage ../development/libraries/openfx {}; + + openimageio = callPackage ../applications/graphics/openimageio { + stdenv = gcc6Stdenv; + }; + + openimageio2 = callPackage ../applications/graphics/openimageio/2.x.nix { }; + + openjump = callPackage ../applications/misc/openjump { }; + + openorienteering-mapper = libsForQt5.callPackage ../applications/gis/openorienteering-mapper { }; + + openscad = libsForQt5.callPackage ../applications/graphics/openscad {}; + + opentimestamps-client = python3Packages.callPackage ../tools/misc/opentimestamps-client {}; + + opentx = callPackage ../applications/misc/opentx { + gcc-arm-embedded = pkgsCross.arm-embedded.buildPackages.gcc; + binutils-arm-embedded = pkgsCross.arm-embedded.buildPackages.binutils; + }; + + opera = callPackage ../applications/networking/browsers/opera {}; + + orca = python3Packages.callPackage ../applications/misc/orca { + inherit (pkgs) pkgconfig; + inherit (gnome3) yelp-tools; + }; + + osm2xmap = callPackage ../applications/misc/osm2xmap { + libyamlcpp = libyamlcpp_0_3; + }; + + osmctools = callPackage ../applications/misc/osmctools { }; + + osmium-tool = callPackage ../applications/misc/osmium-tool { }; + + owamp = callPackage ../applications/networking/owamp { }; + + vivaldi = callPackage ../applications/networking/browsers/vivaldi {}; + + vivaldi-ffmpeg-codecs = callPackage ../applications/networking/browsers/vivaldi/ffmpeg-codecs.nix {}; + + vivaldi-widevine = callPackage ../applications/networking/browsers/vivaldi/widevine.nix { }; + + openmpt123 = callPackage ../applications/audio/openmpt123 { }; + + opusfile = callPackage ../applications/audio/opusfile { }; + + opusTools = callPackage ../applications/audio/opus-tools { }; + + orpie = callPackage ../applications/misc/orpie { + gsl = gsl_1; + ocamlPackages = ocaml-ng.ocamlPackages_4_02; + }; + + osmo = callPackage ../applications/office/osmo { }; + + osquery = callPackage ../tools/system/osquery { }; + + palemoon = callPackage ../applications/networking/browsers/palemoon { + # https://forum.palemoon.org/viewtopic.php?f=57&t=15296#p111146 + stdenv = gcc49Stdenv; + }; + + pamix = callPackage ../applications/audio/pamix { }; + + pamixer = callPackage ../applications/audio/pamixer { }; + + ncpamixer = callPackage ../applications/audio/ncpamixer { }; + + pan = callPackage ../applications/networking/newsreaders/pan { }; + + panotools = callPackage ../applications/graphics/panotools { }; + + paprefs = callPackage ../applications/audio/paprefs { }; + + pavucontrol = callPackage ../applications/audio/pavucontrol { }; + + paraview = libsForQt5.callPackage ../applications/graphics/paraview { }; + + parlatype = callPackage ../applications/audio/parlatype { }; + + packet = callPackage ../development/tools/packet { }; + + pb_cli = callPackage ../tools/misc/pb_cli {}; + + capture = callPackage ../tools/misc/capture {}; + + pbrt = callPackage ../applications/graphics/pbrt { }; + + pcsxr = callPackage ../misc/emulators/pcsxr { + ffmpeg = ffmpeg_2; + }; + + pcsx2 = pkgsi686Linux.callPackage ../misc/emulators/pcsx2 { }; + + pekwm = callPackage ../applications/window-managers/pekwm { }; + + pencil = callPackage ../applications/graphics/pencil { + }; + + perseus = callPackage ../applications/science/math/perseus {}; + + petrifoo = callPackage ../applications/audio/petrifoo { + inherit (gnome2) libgnomecanvas; + }; + + pdfcpu = callPackage ../applications/graphics/pdfcpu { }; + pdftk = callPackage ../tools/typesetting/pdftk { }; + pdfgrep = callPackage ../tools/typesetting/pdfgrep { }; + + pdfpc = callPackage ../applications/misc/pdfpc { + inherit (gst_all_1) gstreamer gst-plugins-base; + }; + + peek = callPackage ../applications/video/peek { }; + + pflask = callPackage ../os-specific/linux/pflask {}; + + photoqt = libsForQt5.callPackage ../applications/graphics/photoqt { }; + + photoflow = callPackage ../applications/graphics/photoflow { }; + + phototonic = libsForQt5.callPackage ../applications/graphics/phototonic { }; + + phrasendrescher = callPackage ../tools/security/phrasendrescher { }; + + phraseapp-client = callPackage ../tools/misc/phraseapp-client { }; + + phwmon = callPackage ../applications/misc/phwmon { }; + + pianobar = callPackage ../applications/audio/pianobar { }; + + pianobooster = callPackage ../applications/audio/pianobooster { }; + + picard = callPackage ../applications/audio/picard { }; + + picocom = callPackage ../tools/misc/picocom { + inherit (darwin.apple_sdk.frameworks) IOKit; + }; + + pidgin = callPackage ../applications/networking/instant-messengers/pidgin { + openssl = if config.pidgin.openssl or true then openssl else null; + gnutls = if config.pidgin.gnutls or false then gnutls else null; + libgcrypt = if config.pidgin.gnutls or false then libgcrypt else null; + startupnotification = libstartup_notification; + plugins = []; + }; + + pidgin-latex = callPackage ../applications/networking/instant-messengers/pidgin-plugins/pidgin-latex { + texLive = texlive.combined.scheme-basic; + }; + + pidgin-msn-pecan = callPackage ../applications/networking/instant-messengers/pidgin-plugins/msn-pecan { }; + + pidgin-mra = callPackage ../applications/networking/instant-messengers/pidgin-plugins/pidgin-mra { }; + + pidgin-skypeweb = callPackage ../applications/networking/instant-messengers/pidgin-plugins/pidgin-skypeweb { }; + + pidgin-carbons = callPackage ../applications/networking/instant-messengers/pidgin-plugins/carbons { }; + + pidgin-xmpp-receipts = callPackage ../applications/networking/instant-messengers/pidgin-plugins/pidgin-xmpp-receipts { }; + + pidgin-otr = callPackage ../applications/networking/instant-messengers/pidgin-plugins/otr { }; + + pidgin-osd = callPackage ../applications/networking/instant-messengers/pidgin-plugins/pidgin-osd { }; + + pidgin-sipe = callPackage ../applications/networking/instant-messengers/pidgin-plugins/sipe { }; + + pidgin-window-merge = callPackage ../applications/networking/instant-messengers/pidgin-plugins/window-merge { }; + + purple-discord = callPackage ../applications/networking/instant-messengers/pidgin-plugins/purple-discord { }; + + purple-hangouts = callPackage ../applications/networking/instant-messengers/pidgin-plugins/purple-hangouts { }; + + purple-lurch = callPackage ../applications/networking/instant-messengers/pidgin-plugins/purple-lurch { }; + + purple-matrix = callPackage ../applications/networking/instant-messengers/pidgin-plugins/purple-matrix { }; + + purple-plugin-pack = callPackage ../applications/networking/instant-messengers/pidgin-plugins/purple-plugin-pack { }; + + purple-vk-plugin = callPackage ../applications/networking/instant-messengers/pidgin-plugins/purple-vk-plugin { }; + + purple-xmpp-http-upload = callPackage ../applications/networking/instant-messengers/pidgin-plugins/purple-xmpp-http-upload { }; + + telegram-purple = callPackage ../applications/networking/instant-messengers/pidgin-plugins/telegram-purple { }; + + toxprpl = callPackage ../applications/networking/instant-messengers/pidgin-plugins/tox-prpl { + libtoxcore = libtoxcore-new; + }; + + pidgin-opensteamworks = callPackage ../applications/networking/instant-messengers/pidgin-plugins/pidgin-opensteamworks { }; + + purple-facebook = callPackage ../applications/networking/instant-messengers/pidgin-plugins/purple-facebook { }; + + pithos = callPackage ../applications/audio/pithos { + pythonPackages = python3Packages; + }; + + pinfo = callPackage ../applications/misc/pinfo { }; + + pinpoint = callPackage ../applications/office/pinpoint { }; + + pinta = callPackage ../applications/graphics/pinta { + gtksharp = gtk-sharp-2_0; + }; + + plex-media-player = libsForQt59.callPackage ../applications/video/plex-media-player { }; + + plover = recurseIntoAttrs (callPackage ../applications/misc/plover { }); + + plugin-torture = callPackage ../applications/audio/plugin-torture { }; + + pmenu = callPackage ../applications/misc/pmenu { }; + + polar-bookshelf = callPackage ../applications/misc/polar-bookshelf { }; + + poezio = python3Packages.poezio; + + pommed_light = callPackage ../os-specific/linux/pommed-light {}; + + polymake = callPackage ../applications/science/math/polymake { }; + + pond = callPackage ../applications/networking/instant-messengers/pond { }; + + ponymix = callPackage ../applications/audio/ponymix { }; + + potrace = callPackage ../applications/graphics/potrace {}; + + posterazor = callPackage ../applications/misc/posterazor { }; + + pqiv = callPackage ../applications/graphics/pqiv { }; + + qiv = callPackage ../applications/graphics/qiv { }; + + processing = callPackage ../applications/graphics/processing { + jdk = oraclejdk8; + }; + + # perhaps there are better apps for this task? It's how I had configured my preivous system. + # And I don't want to rewrite all rules + procmail = callPackage ../applications/misc/procmail { }; + + profanity = callPackage ../applications/networking/instant-messengers/profanity ({ + python = python3; + } // (config.profanity or {})); + + properties-cpp = callPackage ../development/libraries/properties-cpp { }; + + protonmail-bridge = libsForQt512.callPackage ../applications/networking/protonmail-bridge { }; + + protonvpn-cli = callPackage ../applications/networking/protonvpn-cli { }; + + ps2client = callPackage ../applications/networking/ps2client { }; + + psi = callPackage ../applications/networking/instant-messengers/psi { }; + + psi-plus = callPackage ../applications/networking/instant-messengers/psi-plus { }; + + psol = callPackage ../development/libraries/psol { }; + + pstree = callPackage ../applications/misc/pstree { }; + + ptask = callPackage ../applications/misc/ptask { }; + + pulseaudio-ctl = callPackage ../applications/audio/pulseaudio-ctl { }; + + pulseaudio-dlna = callPackage ../applications/audio/pulseaudio-dlna { }; + + pulseview = libsForQt5.callPackage ../applications/science/electronics/pulseview { }; + + puredata = callPackage ../applications/audio/puredata { }; + puredata-with-plugins = plugins: callPackage ../applications/audio/puredata/wrapper.nix { inherit plugins; }; + + puremapping = callPackage ../applications/audio/pd-plugins/puremapping { }; + + pybitmessage = callPackage ../applications/networking/instant-messengers/pybitmessage { }; + + pythonmagick = callPackage ../applications/graphics/PythonMagick { }; + + qbittorrent = libsForQt5.callPackage ../applications/networking/p2p/qbittorrent { }; + + qcomicbook = libsForQt5.callPackage ../applications/graphics/qcomicbook { }; + + eiskaltdcpp = callPackage ../applications/networking/p2p/eiskaltdcpp { + lua5 = lua5_1; + miniupnpc = miniupnpc_1; + }; + + qdirstat = libsForQt5.callPackage ../applications/misc/qdirstat {}; + + qemu = callPackage ../applications/virtualization/qemu { + inherit (darwin.apple_sdk.frameworks) CoreServices Cocoa Hypervisor; + inherit (darwin.stubs) rez setfile; + python = python3; + }; + + qgis-unwrapped = libsForQt5.callPackage ../applications/gis/qgis/unwrapped.nix { + withGrass = false; + }; + + qgis = callPackage ../applications/gis/qgis { }; + + qgroundcontrol = libsForQt5.callPackage ../applications/science/robotics/qgroundcontrol { }; + + qjackctl = libsForQt5.callPackage ../applications/audio/qjackctl { }; + + qlandkartegt = libsForQt5.callPackage ../applications/misc/qlandkartegt {}; + + garmindev = callPackage ../applications/misc/qlandkartegt/garmindev.nix {}; + + qmapshack = libsForQt5.callPackage ../applications/misc/qmapshack { }; + + qmediathekview = libsForQt5.callPackage ../applications/video/qmediathekview { }; + + qmetro = callPackage ../applications/misc/qmetro { }; + + qmidinet = callPackage ../applications/audio/qmidinet { }; + + qmidiroute = callPackage ../applications/audio/qmidiroute { }; + + qmmp = libsForQt5.callPackage ../applications/audio/qmmp { }; + + qnotero = callPackage ../applications/office/qnotero { }; + + qrcode = callPackage ../tools/graphics/qrcode {}; + + qsampler = libsForQt5.callPackage ../applications/audio/qsampler { }; + + qscreenshot = callPackage ../applications/graphics/qscreenshot { + inherit (darwin.apple_sdk.frameworks) Carbon; + qt = qt4; + }; + + qsstv = qt5.callPackage ../applications/radio/qsstv { }; + + qsyncthingtray = libsForQt5.callPackage ../applications/misc/qsyncthingtray { }; + + qstopmotion = libsForQt5.callPackage ../applications/video/qstopmotion { }; + + qsynth = libsForQt5.callPackage ../applications/audio/qsynth { }; + + qtbitcointrader = callPackage ../applications/misc/qtbitcointrader { }; + + qtchan = libsForQt5.callPackage ../applications/networking/browsers/qtchan { }; + + qtox = libsForQt5.callPackage ../applications/networking/instant-messengers/qtox { }; + + qtpass = libsForQt5.callPackage ../applications/misc/qtpass { }; + + qtractor = libsForQt5.callPackage ../applications/audio/qtractor { }; + + qtscrobbler = callPackage ../applications/audio/qtscrobbler { }; + + quantomatic = callPackage ../applications/science/physics/quantomatic { }; + + quassel = libsForQt5.callPackage ../applications/networking/irc/quassel { + inherit (gnome3) dconf; + }; + + quasselClient = quassel.override { + monolithic = false; + client = true; + tag = "-client-kf5"; + }; + + quasselDaemon = quassel.override { + monolithic = false; + daemon = true; + withKDE = false; + tag = "-daemon-qt5"; + }; + + quirc = callPackage ../tools/graphics/quirc {}; + + quilter = callPackage ../applications/editors/quilter { }; + + quiterss = libsForQt5.callPackage ../applications/networking/newsreaders/quiterss {}; + + falkon = libsForQt5.callPackage ../applications/networking/browsers/falkon { }; + + quodlibet = callPackage ../applications/audio/quodlibet { + keybinder3 = null; + libmodplug = null; + kakasi = null; + libappindicator-gtk3 = null; + }; + + quodlibet-without-gst-plugins = quodlibet.override { + withGstPlugins = false; + tag = "-without-gst-plugins"; + }; + + quodlibet-xine = quodlibet.override { xineBackend = true; tag = "-xine"; }; + + quodlibet-full = quodlibet.override { + inherit gtksourceview webkitgtk; + withDbusPython = true; + withPyInotify = true; + withMusicBrainzNgs = true; + withPahoMqtt = true; + keybinder3 = keybinder3; + libmodplug = libmodplug; + kakasi = kakasi; + libappindicator-gtk3 = libappindicator-gtk3; + tag = "-full"; + }; + + quodlibet-xine-full = quodlibet-full.override { xineBackend = true; tag = "-xine-full"; }; + + qutebrowser = libsForQt5.callPackage ../applications/networking/browsers/qutebrowser { }; + + rabbitvcs = callPackage ../applications/version-management/rabbitvcs {}; + + rakarrack = callPackage ../applications/audio/rakarrack { + fltk = fltk13; + }; + + renoise = callPackage ../applications/audio/renoise {}; + + radiotray-ng = callPackage ../applications/audio/radiotray-ng { + wxGTK = wxGTK30; + }; + + railcar = callPackage ../applications/virtualization/railcar {}; + + rapcad = libsForQt5.callPackage ../applications/graphics/rapcad { boost = boost159; }; + + rapid-photo-downloader = libsForQt5.callPackage ../applications/graphics/rapid-photo-downloader { }; + + rapidsvn = callPackage ../applications/version-management/rapidsvn { }; + + ratmen = callPackage ../tools/X11/ratmen {}; + + ratox = callPackage ../applications/networking/instant-messengers/ratox { }; + + ratpoison = callPackage ../applications/window-managers/ratpoison { }; + + rawtherapee = callPackage ../applications/graphics/rawtherapee { + fftw = fftwSinglePrec; + }; + + rclone = callPackage ../applications/networking/sync/rclone { }; + + rclone-browser = libsForQt5.callPackage ../applications/networking/sync/rclone/browser.nix { }; + + rcs = callPackage ../applications/version-management/rcs { }; + + rdesktop = callPackage ../applications/networking/remote/rdesktop { }; + + rdedup = callPackage ../tools/backup/rdedup { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + rdup = callPackage ../tools/backup/rdup { }; + + reaper = callPackage ../applications/audio/reaper { }; + + recode = callPackage ../tools/text/recode { }; + + rednotebook = python3Packages.callPackage ../applications/editors/rednotebook { }; + + remotebox = callPackage ../applications/virtualization/remotebox { }; + + retroshare = libsForQt5.callPackage ../applications/networking/p2p/retroshare { }; + retroshare06 = retroshare; + + ricochet = libsForQt5.callPackage ../applications/networking/instant-messengers/ricochet { }; + + ries = callPackage ../applications/science/math/ries { }; + + ripser = callPackage ../applications/science/math/ripser { }; + + rkt = callPackage ../applications/virtualization/rkt { }; + + rkdeveloptool = callPackage ../misc/rkdeveloptool { }; + + rofi-unwrapped = callPackage ../applications/misc/rofi { }; + rofi = callPackage ../applications/misc/rofi/wrapper.nix { }; + + rofi-pass = callPackage ../tools/security/pass/rofi-pass.nix { }; + + rofi-menugen = callPackage ../applications/misc/rofi-menugen { }; + + rofi-systemd = callPackage ../tools/system/rofi-systemd { }; + + rootlesskit = callPackage ../tools/virtualization/rootlesskit {}; + + rpcs3 = libsForQt5.callPackage ../misc/emulators/rpcs3 { }; + + rstudio = libsForQt5.callPackage ../applications/editors/rstudio { + boost = boost166; + llvmPackages = llvmPackages_7; + }; + + rsync = callPackage ../applications/networking/sync/rsync (config.rsync or {}); + rrsync = callPackage ../applications/networking/sync/rsync/rrsync.nix {}; + + rtl_433 = callPackage ../applications/radio/rtl_433 { }; + + rtl-sdr = callPackage ../applications/radio/rtl-sdr { }; + + rtv = callPackage ../applications/misc/rtv { }; + + rubyripper = callPackage ../applications/audio/rubyripper {}; + + runc = callPackage ../applications/virtualization/runc {}; + + rxvt = callPackage ../applications/misc/rxvt { }; + + # urxvt + rxvt_unicode = callPackage ../applications/misc/rxvt_unicode { }; + + rxvt_unicode-with-plugins = callPackage ../applications/misc/rxvt_unicode/wrapper.nix { + plugins = [ + urxvt_autocomplete_all_the_things + urxvt_perl + urxvt_perls + urxvt_tabbedex + urxvt_font_size + urxvt_theme_switch + urxvt_vtwheel + ]; + }; + + # urxvt plugins + urxvt_autocomplete_all_the_things = callPackage ../applications/misc/rxvt_unicode-plugins/urxvt-autocomplete-all-the-things { }; + urxvt_perl = callPackage ../applications/misc/rxvt_unicode-plugins/urxvt-perl { }; + urxvt_perls = callPackage ../applications/misc/rxvt_unicode-plugins/urxvt-perls { }; + urxvt_tabbedex = callPackage ../applications/misc/rxvt_unicode-plugins/urxvt-tabbedex { }; + urxvt_font_size = callPackage ../applications/misc/rxvt_unicode-plugins/urxvt-font-size { }; + urxvt_theme_switch = callPackage ../applications/misc/rxvt_unicode-plugins/urxvt-theme-switch { }; + urxvt_vtwheel = callPackage ../applications/misc/rxvt_unicode-plugins/urxvt-vtwheel.nix { }; + + uade123 = callPackage ../applications/audio/uade123 {}; + + udevil = callPackage ../applications/misc/udevil {}; + + udiskie = callPackage ../applications/misc/udiskie { }; + + sakura = callPackage ../applications/misc/sakura { }; + + sayonara = callPackage ../applications/audio/sayonara { }; + + sbagen = callPackage ../applications/misc/sbagen { }; + + scantailor = callPackage ../applications/graphics/scantailor { }; + + scantailor-advanced = qt5.callPackage ../applications/graphics/scantailor/advanced.nix { }; + + sc-im = callPackage ../applications/misc/sc-im { }; + + scite = callPackage ../applications/editors/scite { }; + + scribus = callPackage ../applications/office/scribus { + inherit (gnome2) libart_lgpl; + }; + + scribusUnstable = libsForQt5.callPackage ../applications/office/scribus/unstable.nix { }; + + seafile-client = libsForQt5.callPackage ../applications/networking/seafile-client { }; + + seeks = callPackage ../tools/networking/p2p/seeks { + protobuf = protobuf3_1; + }; + + seg3d = callPackage ../applications/graphics/seg3d { + wxGTK = wxGTK28.override { unicode = false; }; + }; + + sent = callPackage ../applications/misc/sent { }; + + seq24 = callPackage ../applications/audio/seq24 { }; + + setbfree = callPackage ../applications/audio/setbfree { }; + + sfxr = callPackage ../applications/audio/sfxr { }; + + sfxr-qt = libsForQt5.callPackage ../applications/audio/sfxr-qt { }; + + shadowfox = callPackage ../tools/networking/shadowfox { }; + + shfmt = callPackage ../tools/text/shfmt { }; + + shutter = callPackage ../applications/graphics/shutter { }; + + simple-scan = gnome3.simple-scan; + + siproxd = callPackage ../applications/networking/siproxd { }; + + skypeforlinux = callPackage ../applications/networking/instant-messengers/skypeforlinux { }; + + skype4pidgin = callPackage ../applications/networking/instant-messengers/pidgin-plugins/skype4pidgin { }; + + skype_call_recorder = callPackage ../applications/networking/instant-messengers/skype-call-recorder { }; + + SkypeExport = callPackage ../applications/networking/instant-messengers/SkypeExport { }; + + slmenu = callPackage ../applications/misc/slmenu {}; + + slop = callPackage ../tools/misc/slop {}; + + slrn = callPackage ../applications/networking/newsreaders/slrn { }; + + slurp = callPackage ../tools/misc/slurp { }; + + sniproxy = callPackage ../applications/networking/sniproxy { }; + + sooperlooper = callPackage ../applications/audio/sooperlooper { }; + + sops = callPackage ../tools/security/sops { }; + + sorcer = callPackage ../applications/audio/sorcer { }; + + sound-juicer = callPackage ../applications/audio/sound-juicer { }; + + spice-vdagent = callPackage ../applications/virtualization/spice-vdagent { }; + + spideroak = callPackage ../applications/networking/spideroak { }; + + split2flac = callPackage ../applications/audio/split2flac { }; + + squishyball = callPackage ../applications/audio/squishyball { + ncurses = ncurses5; + }; + + stupidterm = callPackage ../applications/misc/stupidterm { + gtk = gtk3; + }; + + styx = callPackage ../applications/misc/styx { }; + + tecoc = callPackage ../applications/editors/tecoc { }; + + viber = callPackage ../applications/networking/instant-messengers/viber { }; + + wavebox = callPackage ../applications/networking/instant-messengers/wavebox { }; + + sonic-pi = callPackage ../applications/audio/sonic-pi { + ruby = ruby_2_3; + }; + + st = callPackage ../applications/misc/st { + conf = config.st.conf or null; + patches = config.st.patches or []; + extraLibs = config.st.extraLibs or []; + }; + + xst = callPackage ../applications/misc/st/xst.nix { }; + + stag = callPackage ../applications/misc/stag { + curses = ncurses; + }; + + stella = callPackage ../misc/emulators/stella { }; + + linuxstopmotion = callPackage ../applications/video/linuxstopmotion { }; + + sweethome3d = recurseIntoAttrs ( (callPackage ../applications/misc/sweethome3d { }) + // (callPackage ../applications/misc/sweethome3d/editors.nix { + sweethome3dApp = sweethome3d.application; + }) + ); + + swingsane = callPackage ../applications/graphics/swingsane { }; + + sxiv = callPackage ../applications/graphics/sxiv { }; + + resilio-sync = callPackage ../applications/networking/resilio-sync { }; + + dropbox = callPackage ../applications/networking/dropbox { }; + + dropbox-cli = callPackage ../applications/networking/dropbox/cli.nix { }; + + maestral = callPackage ../applications/networking/maestral { }; + + maestral-gui = libsForQt5.callPackage ../applications/networking/maestral { withGui = true; }; + + insync = callPackage ../applications/networking/insync { }; + + libstrangle = callPackage ../tools/X11/libstrangle { + stdenv = stdenv_32bit; + }; + + lightdm = libsForQt5.callPackage ../applications/display-managers/lightdm { }; + + lightdm_qt = lightdm.override { withQt5 = true; }; + + lightdm-enso-os-greeter = callPackage ../applications/display-managers/lightdm-enso-os-greeter { + inherit (xorg) libX11 libXdmcp libpthreadstubs; + }; + + lightdm_gtk_greeter = callPackage ../applications/display-managers/lightdm/gtk-greeter.nix { + inherit (xfce) exo; + }; + + lightdm-mini-greeter = callPackage ../applications/display-managers/lightdm-mini-greeter { }; + + ly = callPackage ../applications/display-managers/ly { }; + + slic3r = callPackage ../applications/misc/slic3r { }; + + curaengine_stable = callPackage ../applications/misc/curaengine/stable.nix { }; + cura_stable = callPackage ../applications/misc/cura/stable.nix { + curaengine = curaengine_stable; + }; + + curaengine = callPackage ../applications/misc/curaengine { inherit (python3.pkgs) libarcus; }; + + cura = qt5.callPackage ../applications/misc/cura { }; + + curaPlugins = callPackage ../applications/misc/cura/plugins.nix { }; + + curaLulzbot = qt5.callPackage ../applications/misc/cura/lulzbot/default.nix { }; + + curaByDagoma = callPackage ../applications/misc/curabydagoma { }; + + peru = callPackage ../applications/version-management/peru {}; + + petrinizer = haskellPackages.callPackage ../applications/science/logic/petrinizer {}; + + pmidi = callPackage ../applications/audio/pmidi { }; + + printrun = callPackage ../applications/misc/printrun { }; + + prusa-slicer = callPackage ../applications/misc/prusa-slicer { }; + + sddm = libsForQt5.callPackage ../applications/display-managers/sddm { }; + + skrooge = libsForQt5.callPackage ../applications/office/skrooge {}; + + slim = callPackage ../applications/display-managers/slim { + libpng = libpng12; + }; + + smartgithg = callPackage ../applications/version-management/smartgithg { + jre = openjdk11; + }; + + slimThemes = recurseIntoAttrs (callPackage ../applications/display-managers/slim/themes.nix {}); + + smartdeblur = callPackage ../applications/graphics/smartdeblur { }; + + snapper = callPackage ../tools/misc/snapper { }; + + snd = callPackage ../applications/audio/snd { }; + + shntool = callPackage ../applications/audio/shntool { }; + + sipp = callPackage ../development/tools/misc/sipp { }; + + skanlite = libsForQt5.callPackage ../applications/office/skanlite { }; + + sonic-visualiser = libsForQt5.callPackage ../applications/audio/sonic-visualiser { + inherit (pkgs.vamp) vampSDK; + }; + + soulseekqt = libsForQt5.callPackage ../applications/networking/p2p/soulseekqt { }; + + sox = callPackage ../applications/misc/audio/sox { + inherit (darwin.apple_sdk.frameworks) CoreAudio; + }; + + soxr = callPackage ../applications/misc/audio/soxr { }; + + spek = callPackage ../applications/audio/spek { + ffmpeg = ffmpeg_2; + }; + + spotify = callPackage ../applications/audio/spotify { + libgcrypt = libgcrypt_1_5; + libpng = libpng12; + curl = curl.override { + sslSupport = false; gnutlsSupport = true; + }; + }; + + libspotify = callPackage ../development/libraries/libspotify (config.libspotify or {}); + + sourcetrail = callPackage ../development/tools/sourcetrail { }; + + spotifywm = callPackage ../applications/audio/spotifywm { }; + + squeezelite = callPackage ../applications/audio/squeezelite { }; + + ltunify = callPackage ../tools/misc/ltunify { }; + + src = callPackage ../applications/version-management/src { + git = gitMinimal; + }; + + ssr = callPackage ../applications/audio/soundscape-renderer {}; + + ssrc = callPackage ../applications/audio/ssrc { }; + + stalonetray = callPackage ../applications/window-managers/stalonetray {}; + + inherit (ocamlPackages) stog; + + stp = callPackage ../applications/science/logic/stp { + bison = bison2; + }; + + stretchly = callPackage ../applications/misc/stretchly { + inherit (gnome2) GConf; + }; + + stumpish = callPackage ../applications/window-managers/stumpish {}; + + stumpwm = callPackage ../applications/window-managers/stumpwm { + version = "latest"; + }; + + stumpwm-git = stumpwm.override { + version = "git"; + inherit sbcl lispPackages; + }; + + sublime = callPackage ../applications/editors/sublime/2 { }; + + sublime3Packages = recurseIntoAttrs (callPackage ../applications/editors/sublime/3/packages.nix { }); + + sublime3 = sublime3Packages.sublime3; + + sublime3-dev = sublime3Packages.sublime3-dev; + + inherit (callPackage ../applications/version-management/sublime-merge {}) + sublime-merge + sublime-merge-dev; + + inherit (callPackages ../applications/version-management/subversion { sasl = cyrus_sasl; }) + subversion19 subversion_1_10 subversion; + + subversionClient = appendToName "client" (pkgs.subversion.override { + bdbSupport = false; + perlBindings = true; + pythonBindings = true; + }); + + subunit = callPackage ../development/libraries/subunit { }; + + surf = callPackage ../applications/networking/browsers/surf { gtk = gtk2; }; + + surf-display = callPackage ../desktops/surf-display { }; + + sunvox = callPackage ../applications/audio/sunvox { }; + + swh_lv2 = callPackage ../applications/audio/swh-lv2 { }; + + swift-im = libsForQt5.callPackage ../applications/networking/instant-messengers/swift-im { + inherit (gnome2) GConf; + }; + + sylpheed = callPackage ../applications/networking/mailreaders/sylpheed { }; + + symlinks = callPackage ../tools/system/symlinks { }; + + syncplay = python3.pkgs.callPackage ../applications/networking/syncplay { }; + + inherit (callPackages ../applications/networking/syncthing { }) + syncthing + syncthing-cli + syncthing-discovery + syncthing-relay; + + syncthing-gtk = python2Packages.callPackage ../applications/networking/syncthing-gtk { }; + + syncthing-tray = callPackage ../applications/misc/syncthing-tray { }; + + syncthingtray = libsForQt5.callPackage ../applications/misc/syncthingtray { }; + syncthingtray-minumal = libsForQt5.callPackage ../applications/misc/syncthingtray { + webviewSupport = false; + jsSupport = false; + kioPluginSupport = false; + plasmoidSupport = false; + systemdSupport = true; + }; + + synergy = callPackage ../applications/misc/synergy { + stdenv = if stdenv.cc.isClang then llvmPackages_5.stdenv else stdenv; + inherit (darwin.apple_sdk.frameworks) ApplicationServices Carbon Cocoa CoreServices ScreenSaver; + }; + + tabbed = callPackage ../applications/window-managers/tabbed { + # if you prefer a custom config, write the config.h in tabbed.config.h + # and enable + # customConfig = builtins.readFile ./tabbed.config.h; + }; + + taffybar = callPackage ../applications/window-managers/taffybar { + inherit (haskellPackages) ghcWithPackages; + }; + + tagainijisho = callPackage ../applications/office/tagainijisho {}; + + tahoe-lafs = callPackage ../tools/networking/p2p/tahoe-lafs {}; + + tailor = callPackage ../applications/version-management/tailor {}; + + tangogps = callPackage ../applications/misc/tangogps { + gconf = gnome2.GConf; + }; + + tambura = callPackage ../applications/audio/tambura { }; + + teamspeak_client = libsForQt512.callPackage ../applications/networking/instant-messengers/teamspeak/client.nix { }; + teamspeak_server = callPackage ../applications/networking/instant-messengers/teamspeak/server.nix { }; + + taskell = callPackage ../applications/misc/taskell { }; + + taskjuggler = callPackage ../applications/misc/taskjuggler { }; + + tabula = callPackage ../applications/misc/tabula { }; + + tasknc = callPackage ../applications/misc/tasknc { }; + + taskwarrior = callPackage ../applications/misc/taskwarrior { }; + + tasksh = callPackage ../applications/misc/tasksh { }; + + taskserver = callPackage ../servers/misc/taskserver { }; + + taskopen = callPackage ../applications/misc/taskopen { }; + + # TODO (@primeos): Remove after the 19.09 branch-off: + tdesktopPackages = throw '' + The attributes "tdesktopPackages.*" where removed as the preview version + will not be maintained anymore (there are regular stable releases and we + depend on the patches from Arch Linux which only track the stable version + as well). Please switch to "tdesktop" (stable version). + ''; + tdesktop = qt5.callPackage ../applications/networking/instant-messengers/telegram/tdesktop { }; + + telepathy-gabble = callPackage ../applications/networking/instant-messengers/telepathy/gabble { }; + + telepathy-haze = callPackage ../applications/networking/instant-messengers/telepathy/haze {}; + + telepathy-logger = callPackage ../applications/networking/instant-messengers/telepathy/logger {}; + + telepathy-mission-control = callPackage ../applications/networking/instant-messengers/telepathy/mission-control { }; + + telepathy-salut = callPackage ../applications/networking/instant-messengers/telepathy/salut {}; + + telepathy-idle = callPackage ../applications/networking/instant-messengers/telepathy/idle {}; + + tendermint = callPackage ../tools/networking/tendermint {}; + + termdown = (newScope pythonPackages) ../applications/misc/termdown { }; + + terminal-notifier = callPackage ../applications/misc/terminal-notifier {}; + + terminator = callPackage ../applications/misc/terminator { }; + + terminus = callPackage ../applications/misc/terminus { }; + + lxterminal = callPackage ../applications/misc/lxterminal { }; + + aminal = callPackage ../applications/misc/aminal { + inherit (darwin.apple_sdk.frameworks) Carbon Cocoa Kernel; + }; + + termite-unwrapped = callPackage ../applications/misc/termite { }; + + termite = callPackage ../applications/misc/termite/wrapper.nix { termite = termite-unwrapped; }; + + termtosvg = callPackage ../tools/misc/termtosvg { }; + + inherit (callPackage ../applications/graphics/tesseract {}) + tesseract3 + tesseract4; + tesseract = tesseract3; + + tetraproc = callPackage ../applications/audio/tetraproc { }; + + thinkingRock = callPackage ../applications/misc/thinking-rock { }; + + thonny = callPackage ../applications/editors/thonny { }; + + thunderbird = callPackage ../applications/networking/mailreaders/thunderbird { + inherit (gnome2) libIDL; + libpng = libpng_apng; + enableGTK3 = true; + }; + + thunderbolt = callPackage ../os-specific/linux/thunderbolt {}; + + thunderbird-bin = callPackage ../applications/networking/mailreaders/thunderbird-bin { + gconf = pkgs.gnome2.GConf; + inherit (pkgs.gnome2) libgnome libgnomeui; + }; + + ticpp = callPackage ../development/libraries/ticpp { }; + + tig = gitAndTools.tig; + + tilda = callPackage ../applications/misc/tilda { + gtk = gtk3; + }; + + timbreid = callPackage ../applications/audio/pd-plugins/timbreid { + fftw = fftwSinglePrec; + }; + + timewarrior = callPackage ../applications/misc/timewarrior { }; + + timidity = callPackage ../tools/misc/timidity { }; + + tint2 = callPackage ../applications/misc/tint2 { }; + + tixati = callPackage ../applications/networking/p2p/tixati { }; + + tkcvs = callPackage ../applications/version-management/tkcvs { }; + + tla = callPackage ../applications/version-management/arch { }; + + tlf = callPackage ../applications/radio/tlf { }; + + tlp = callPackage ../tools/misc/tlp { + inherit (linuxPackages) x86_energy_perf_policy; + }; + + tmatrix = callPackage ../applications/misc/tmatrix { }; + + tnef = callPackage ../applications/misc/tnef { }; + + todiff = callPackage ../applications/misc/todiff { }; + + todo-txt-cli = callPackage ../applications/office/todo.txt-cli { }; + + todoman = callPackage ../applications/office/todoman { }; + + toggldesktop = libsForQt5.callPackage ../applications/misc/toggldesktop { }; + + tomahawk = callPackage ../applications/audio/tomahawk ({ + taglib = taglib_1_9; + quazip = quazip_qt4; + boost = boost155; + } // (config.tomahawk or {})); + + topydo = callPackage ../applications/misc/topydo {}; + + torchPackages = recurseIntoAttrs ( callPackage ../applications/science/machine-learning/torch { + lua = luajit ; + } ); + + torch-repl = lib.setName "torch-repl" torchPackages.trepl; + + torchat = callPackage ../applications/networking/instant-messengers/torchat { + inherit (pythonPackages) wrapPython wxPython; + }; + + torrential = callPackage ../applications/networking/p2p/torrential { }; + + tortoisehg = callPackage ../applications/version-management/tortoisehg { }; + + toot = callPackage ../applications/misc/toot { }; + + tootle = callPackage ../applications/misc/tootle { }; + + toxic = callPackage ../applications/networking/instant-messengers/toxic { }; + + toxiproxy = callPackage ../development/tools/toxiproxy { }; + + tqsl = callPackage ../applications/radio/tqsl { }; + trustedqsl = tqsl; # Alias added 2019-02-10 + + transcode = callPackage ../applications/audio/transcode { }; + + transcribe = callPackage ../applications/audio/transcribe { }; + + transmission = callPackage ../applications/networking/p2p/transmission { }; + transmission-gtk = transmission.override { enableGTK3 = true; }; + + transmission-remote-cli = callPackage ../applications/networking/p2p/transmission-remote-cli {}; + transmission-remote-gtk = callPackage ../applications/networking/p2p/transmission-remote-gtk {}; + + transgui = callPackage ../applications/networking/p2p/transgui { }; + + traverso = libsForQt5.callPackage ../applications/audio/traverso { }; + + trayer = callPackage ../applications/window-managers/trayer { }; + + tree-from-tags = callPackage ../applications/audio/tree-from-tags { }; + + tdrop = callPackage ../applications/misc/tdrop { }; + + tree = callPackage ../tools/system/tree {}; + + treesheets = callPackage ../applications/office/treesheets { wxGTK = wxGTK31; }; + + tribler = callPackage ../applications/networking/p2p/tribler { }; + + trojita = libsForQt5.callPackage ../applications/networking/mailreaders/trojita { }; + + tudu = callPackage ../applications/office/tudu { }; + + tuxguitar = callPackage ../applications/editors/music/tuxguitar { }; + + twister = callPackage ../applications/networking/p2p/twister { + boost = boost160; + }; + + twmn = libsForQt5.callPackage ../applications/misc/twmn { }; + + testssl = callPackage ../applications/networking/testssl { }; + + ulauncher = callPackage ../applications/misc/ulauncher { }; + + umurmur = callPackage ../applications/networking/umurmur { }; + + udocker = pythonPackages.callPackage ../tools/virtualization/udocker { }; + + unigine-valley = callPackage ../applications/graphics/unigine-valley { }; + + inherit (ocaml-ng.ocamlPackages_4_05) unison; + + unpaper = callPackage ../tools/graphics/unpaper { }; + + unison-ucm = callPackage ../development/compilers/unison { }; + + urh = callPackage ../applications/radio/urh { }; + + uuagc = haskell.lib.justStaticExecutables haskellPackages.uuagc; + + uucp = callPackage ../tools/misc/uucp { }; + + uvccapture = callPackage ../applications/video/uvccapture { }; + + uwimap = callPackage ../tools/networking/uwimap { }; + + uzbl = callPackage ../applications/networking/browsers/uzbl { + webkitgtk = webkitgtk24x-gtk2; + }; + + utox = callPackage ../applications/networking/instant-messengers/utox { }; + + valentina = libsForQt5.callPackage ../applications/misc/valentina { }; + + vbindiff = callPackage ../applications/editors/vbindiff { }; + + vcprompt = callPackage ../applications/version-management/vcprompt { }; + + vcv-rack = callPackage ../applications/audio/vcv-rack { }; + + vdirsyncer = callPackage ../tools/misc/vdirsyncer { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + vdirsyncerStable = callPackage ../tools/misc/vdirsyncer/stable.nix { }; + + vdpauinfo = callPackage ../tools/X11/vdpauinfo { }; + + verbiste = callPackage ../applications/misc/verbiste { + inherit (gnome2) libgnomeui; + }; + + vim = callPackage ../applications/editors/vim { + inherit (darwin.apple_sdk.frameworks) Carbon Cocoa; + }; + + vimiv = callPackage ../applications/graphics/vimiv { }; + + macvim = callPackage ../applications/editors/vim/macvim.nix { stdenv = clangStdenv; }; + + vimHugeX = vim_configurable; + + vim_configurable = vimUtils.makeCustomizable (callPackage ../applications/editors/vim/configurable.nix { + inherit (darwin.apple_sdk.frameworks) CoreServices Cocoa Foundation CoreData; + inherit (darwin) libobjc; + gtk2 = if stdenv.isDarwin then gtk2-x11 else gtk2; + gtk3 = if stdenv.isDarwin then gtk3-x11 else gtk3; + }); + + qpdfview = libsForQt5.callPackage ../applications/misc/qpdfview {}; + + qtile = callPackage ../applications/window-managers/qtile { + inherit (xorg) libxcb; + }; + + qvim = lowPrio (callPackage ../applications/editors/vim/qvim.nix { + features = "huge"; # one of tiny, small, normal, big or huge + lua = pkgs.lua5; + flags = [ "python" "X11" ]; # only flag "X11" by now + }); + + vimpc = callPackage ../applications/audio/vimpc { }; + + wrapNeovim = callPackage ../applications/editors/neovim/wrapper.nix { }; + + neovim-unwrapped = callPackage ../applications/editors/neovim { + lua = + # neovim doesn't work with luajit on aarch64: https://github.com/neovim/neovim/issues/7879 + if stdenv.isAarch64 then lua5_1 else + luajit; + }; + + neovim = wrapNeovim neovim-unwrapped { }; + + neovim-qt = libsForQt5.callPackage ../applications/editors/neovim/qt.nix { }; + + neovim-remote = callPackage ../applications/editors/neovim/neovim-remote.nix { pythonPackages = python3Packages; }; + + vis = callPackage ../applications/editors/vis { + inherit (lua52Packages) lpeg; + }; + + virt-viewer = callPackage ../applications/virtualization/virt-viewer { }; + + virt-top = callPackage ../applications/virtualization/virt-top { }; + + virt-what = callPackage ../applications/virtualization/virt-what { }; + + virtmanager = callPackage ../applications/virtualization/virt-manager { + dconf = gnome3.dconf; + system-libvirt = libvirt; + }; + + virtmanager-qt = libsForQt5.callPackage ../applications/virtualization/virt-manager/qt.nix { + qtermwidget = lxqt.qtermwidget; + }; + + virtinst = callPackage ../applications/virtualization/virtinst {}; + + virtscreen = callPackage ../tools/admin/virtscreen {}; + + virtualbox = libsForQt5.callPackage ../applications/virtualization/virtualbox { + stdenv = stdenv_32bit; + inherit (gnome2) libIDL; + }; + + virtualboxHardened = lowPrio (virtualbox.override { + enableHardening = true; + }); + + virtualboxHeadless = lowPrio (virtualbox.override { + enableHardening = true; + headless = true; + }); + + virtualboxExtpack = callPackage ../applications/virtualization/virtualbox/extpack.nix { }; + + virtualboxWithExtpack = lowPrio (virtualbox.override { + extensionPack = virtualboxExtpack; + }); + + virtualglLib = callPackage ../tools/X11/virtualgl/lib.nix { + fltk = fltk13; + }; + + virtualgl = callPackage ../tools/X11/virtualgl { + virtualglLib_i686 = if stdenv.hostPlatform.system == "x86_64-linux" + then pkgsi686Linux.virtualglLib + else null; + }; + + vpcs = callPackage ../applications/virtualization/vpcs { }; + + primusLib = callPackage ../tools/X11/primus/lib.nix { + nvidia_x11 = linuxPackages.nvidia_x11.override { libsOnly = true; }; + }; + + primus = callPackage ../tools/X11/primus { + stdenv_i686 = pkgsi686Linux.stdenv; + primusLib_i686 = if stdenv.hostPlatform.system == "x86_64-linux" + then pkgsi686Linux.primusLib + else null; + }; + + bumblebee = callPackage ../tools/X11/bumblebee { + nvidia_x11 = linuxPackages.nvidia_x11; + nvidia_x11_i686 = if stdenv.hostPlatform.system == "x86_64-linux" + then pkgsi686Linux.linuxPackages.nvidia_x11.override { libsOnly = true; } + else null; + libglvnd_i686 = if stdenv.hostPlatform.system == "x86_64-linux" + then pkgsi686Linux.libglvnd + else null; + }; + + uvcdynctrl = callPackage ../os-specific/linux/uvcdynctrl { }; + + vkeybd = callPackage ../applications/audio/vkeybd {}; + + vlc = libsForQt5.vlc; + + vlc_qt5 = vlc; + + vmpk = callPackage ../applications/audio/vmpk { }; + + vnstat = callPackage ../applications/networking/vnstat { }; + + vocal = callPackage ../applications/audio/vocal { }; + + vogl = libsForQt5.callPackage ../development/tools/vogl { }; + + volnoti = callPackage ../applications/misc/volnoti { }; + + vorbis-tools = callPackage ../applications/audio/vorbis-tools { }; + + vscode = callPackage ../applications/editors/vscode/vscode.nix { }; + + vscode-with-extensions = callPackage ../applications/editors/vscode/with-extensions.nix {}; + + vscode-utils = callPackage ../misc/vscode-extensions/vscode-utils.nix {}; + + vscode-extensions = recurseIntoAttrs (callPackage ../misc/vscode-extensions {}); + + vscodium = callPackage ../applications/editors/vscode/vscodium.nix { }; + + vue = callPackage ../applications/misc/vue { }; + + vuze = callPackage ../applications/networking/p2p/vuze { }; + + vwm = callPackage ../applications/window-managers/vwm { }; + + vym = qt5.callPackage ../applications/misc/vym { }; + + w3m = callPackage ../applications/networking/browsers/w3m { }; + + # Should always be the version with the most features + w3m-full = w3m; + + # Version without X11 + w3m-nox = w3m.override { + x11Support = false; + imlib2 = imlib2-nox; + }; + + # Version without X11 or graphics + w3m-nographics = w3m.override { + x11Support = false; + graphicsSupport = false; + }; + + # Version for batch text processing, not a good browser + w3m-batch = w3m.override { + graphicsSupport = false; + mouseSupport = false; + x11Support = false; + imlib2 = imlib2-nox; + }; + + watson = callPackage ../applications/office/watson { + pythonPackages = python3Packages; + }; + + way-cooler = callPackage ../applications/window-managers/way-cooler {}; + + wayv = callPackage ../tools/X11/wayv {}; + + webtorrent_desktop = callPackage ../applications/video/webtorrent_desktop {}; + + wrapWeechat = callPackage ../applications/networking/irc/weechat/wrapper.nix { }; + + weechat-unwrapped = callPackage ../applications/networking/irc/weechat { + inherit (darwin) libobjc; + inherit (darwin) libresolv; + guile = guile_2_0; + }; + + weechat = wrapWeechat weechat-unwrapped { }; + + weechatScripts = dontRecurseIntoAttrs (callPackage ../applications/networking/irc/weechat/scripts { }); + + westonLite = weston.override { + pango = null; + freerdp = null; + libunwind = null; + vaapi = null; + libva = null; + libwebp = null; + xwayland = null; + }; + + chatterino2 = libsForQt5.callPackage ../applications/networking/instant-messengers/chatterino2 {}; + + weston = callPackage ../applications/window-managers/weston { }; + + whitebox-tools = callPackage ../applications/gis/whitebox-tools { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + windowlab = callPackage ../applications/window-managers/windowlab { }; + + windowmaker = callPackage ../applications/window-managers/windowmaker { }; + + wily = callPackage ../applications/editors/wily { }; + + winswitch = callPackage ../tools/X11/winswitch { }; + + wings = callPackage ../applications/graphics/wings { + erlang = erlangR21; + }; + + write_stylus = libsForQt5.callPackage ../applications/graphics/write_stylus { }; + + alsamixer.app = callPackage ../applications/window-managers/windowmaker/dockapps/alsamixer.app.nix { }; + + wllvm = callPackage ../development/tools/wllvm { }; + + wmcalclock = callPackage ../applications/window-managers/windowmaker/dockapps/wmcalclock.nix { }; + + wmsm.app = callPackage ../applications/window-managers/windowmaker/dockapps/wmsm.app.nix { }; + + wmsystemtray = callPackage ../applications/window-managers/windowmaker/dockapps/wmsystemtray.nix { }; + + wmname = callPackage ../applications/misc/wmname { }; + + wmctrl = callPackage ../tools/X11/wmctrl { }; + + wmii_hg = callPackage ../applications/window-managers/wmii-hg { }; + + wordnet = callPackage ../applications/misc/wordnet { }; + + wordgrinder = callPackage ../applications/office/wordgrinder { }; + + worker = callPackage ../applications/misc/worker { }; + + workrave = callPackage ../applications/misc/workrave { + inherit (python27Packages) cheetah; + inherit (gst_all_1) gstreamer gst-plugins-base gst-plugins-good; + }; + + worldengine-cli = python3Packages.worldengine; + + wpsoffice = callPackage ../applications/office/wpsoffice {}; + + wrapFirefox = callPackage ../applications/networking/browsers/firefox/wrapper.nix { }; + + wp-cli = callPackage ../development/tools/wp-cli { }; + + retroArchCores = + let + cfg = config.retroarch or {}; + inherit (lib) optional; + in with libretro; + ([ ] + ++ optional (cfg.enable4do or false) _4do + ++ optional (cfg.enableBeetlePCEFast or false) beetle-pce-fast + ++ optional (cfg.enableBeetlePSX or false) beetle-psx + ++ optional (cfg.enableBeetleSaturn or false) beetle-saturn + ++ optional (cfg.enableBsnesMercury or false) bsnes-mercury + ++ optional (cfg.enableDesmume or false) desmume + ++ optional (cfg.enableDolphin or false) dolphin + ++ optional (cfg.enableFBA or false) fba + ++ optional (cfg.enableFceumm or false) fceumm + ++ optional (cfg.enableGambatte or false) gambatte + ++ optional (cfg.enableGenesisPlusGX or false) genesis-plus-gx + ++ optional (cfg.enableHiganSFC or false) higan-sfc + ++ optional (cfg.enableMAME or false) mame + ++ optional (cfg.enableMGBA or false) mgba + ++ optional (cfg.enableMupen64Plus or false) mupen64plus + ++ optional (cfg.enableNestopia or false) nestopia + ++ optional (cfg.enableParallelN64 or false) parallel-n64 + ++ optional (cfg.enablePicodrive or false) picodrive + ++ optional (cfg.enablePrboom or false) prboom + ++ optional (cfg.enablePPSSPP or false) ppsspp + ++ optional (cfg.enableQuickNES or false) quicknes + ++ optional (cfg.enableReicast or false) reicast + ++ optional (cfg.enableScummVM or false) scummvm + ++ optional (cfg.enableSnes9x or false) snes9x + ++ optional (cfg.enableSnes9xNext or false) snes9x-next + ++ optional (cfg.enableStella or false) stella + ++ optional (cfg.enableVbaNext or false) vba-next + ++ optional (cfg.enableVbaM or false) vba-m + + # added on 2017-02-25 due #23163 + ++ optional (cfg.enableMednafenPCEFast or false) + (throw "nix config option enableMednafenPCEFast has been renamed to enableBeetlePCEFast") + ++ optional (cfg.enableMednafenPSX or false) + (throw "nix config option enableMednafenPSX has been renamed to enableBeetlePSX") + ++ optional (cfg.enableMednafenSaturn or false) + (throw "nix config option enableMednafenSaturn has been renamed to enableBeetleSaturn") + ); + + wrapRetroArch = { retroarch }: callPackage ../misc/emulators/retroarch/wrapper.nix { + inherit retroarch; + cores = retroArchCores; + }; + + wrapKodi = { kodi }: callPackage ../applications/video/kodi/wrapper.nix { + inherit kodi; + plugins = let inherit (lib) optional optionals; in with kodiPlugins; + ([] + ++ optional (config.kodi.enableAdvancedLauncher or false) advanced-launcher + ++ optional (config.kodi.enableAdvancedEmulatorLauncher or false) + advanced-emulator-launcher + ++ optionals (config.kodi.enableControllers or false) + (with controllers; + [ default dreamcast gba genesis mouse n64 nes ps snes ]) + ++ optional (config.kodi.enableExodus or false) exodus + ++ optionals (config.kodi.enableHyperLauncher or false) + (with hyper-launcher; [ plugin service pdfreader ]) + ++ optional (config.kodi.enableJoystick or false) joystick + ++ optional (config.kodi.enableOSMCskin or false) osmc-skin + ++ optional (config.kodi.enableSVTPlay or false) svtplay + ++ optional (config.kodi.enableSteamController or false) steam-controller + ++ optional (config.kodi.enableSteamLauncher or false) steam-launcher + ++ optional (config.kodi.enablePVRHTS or false) pvr-hts + ++ optional (config.kodi.enablePVRHDHomeRun or false) pvr-hdhomerun + ++ optional (config.kodi.enablePVRIPTVSimple or false) pvr-iptvsimple + ++ optional (config.kodi.enableInputStreamAdaptive or false) inputstream-adaptive + ++ optional (config.kodi.enableVFSSFTP or false) vfs-sftp + ++ optional (config.kodi.enableVFSLibarchive or false) vfs-libarchive + ); + }; + + wsjtx = qt5.callPackage ../applications/radio/wsjtx { }; + + wtftw = callPackage ../applications/window-managers/wtftw {}; + + wxhexeditor = callPackage ../applications/editors/wxhexeditor { + wxGTK = wxGTK31; + }; + + wxcam = callPackage ../applications/video/wxcam { + inherit (gnome2) libglade; + wxGTK = wxGTK28; + gtk = gtk2; + }; + + x11basic = callPackage ../development/compilers/x11basic { }; + + x11vnc = callPackage ../tools/X11/x11vnc { }; + + x2goclient = libsForQt5.callPackage ../applications/networking/remote/x2goclient { }; + + x2vnc = callPackage ../tools/X11/x2vnc { }; + + x32edit = callPackage ../applications/audio/midas/x32edit.nix {}; + + x42-plugins = callPackage ../applications/audio/x42-plugins { }; + + xannotate = callPackage ../tools/X11/xannotate {}; + + xaos = callPackage ../applications/graphics/xaos { + libpng = libpng12; + }; + + xara = callPackage ../applications/graphics/xara { }; + + xastir = callPackage ../applications/misc/xastir { + rastermagick = imagemagick; + inherit (xorg) libXt; + }; + + xautomation = callPackage ../tools/X11/xautomation { }; + + xawtv = callPackage ../applications/video/xawtv { }; + + xbindkeys = callPackage ../tools/X11/xbindkeys { }; + + xbindkeys-config = callPackage ../tools/X11/xbindkeys-config { + gtk = gtk2; + }; + + kodiPlain = callPackage ../applications/video/kodi { }; + + kodiPlainWayland = callPackage ../applications/video/kodi { useWayland = true; }; + + kodiPlugins = recurseIntoAttrs (callPackage ../applications/video/kodi/plugins.nix {}); + + kodi = wrapKodi { + kodi = kodiPlain; + }; + + kodi-wayland = wrapKodi { + kodi = kodiPlainWayland; + }; + + kodi-cli = callPackage ../tools/misc/kodi-cli { }; + + kodi-retroarch-advanced-launchers = + callPackage ../misc/emulators/retroarch/kodi-advanced-launchers.nix { + cores = retroArchCores; + }; + xbmc-retroarch-advanced-launchers = kodi-retroarch-advanced-launchers; + + xca = libsForQt5.callPackage ../applications/misc/xca { }; + + xcalib = callPackage ../tools/X11/xcalib { }; + + xcape = callPackage ../tools/X11/xcape { }; + + xchainkeys = callPackage ../tools/X11/xchainkeys { }; + + xchm = callPackage ../applications/misc/xchm { }; + + inherit (xorg) xcompmgr; + + compton = callPackage ../applications/window-managers/compton {}; + + xdaliclock = callPackage ../tools/misc/xdaliclock {}; + + xdg-dbus-proxy = callPackage ../development/libraries/xdg-dbus-proxy { }; + + xdg-desktop-portal = callPackage ../development/libraries/xdg-desktop-portal { }; + + xdg-desktop-portal-gtk = callPackage ../development/libraries/xdg-desktop-portal-gtk { }; + + xdg-user-dirs = callPackage ../tools/X11/xdg-user-dirs { }; + + xdg_utils = callPackage ../tools/X11/xdg-utils { + w3m = w3m-batch; + }; + + xdgmenumaker = callPackage ../applications/misc/xdgmenumaker { }; + + xdotool = callPackage ../tools/X11/xdotool { }; + + xenPackages = recurseIntoAttrs (callPackage ../applications/virtualization/xen/packages.nix {}); + + xen = xenPackages.xen-vanilla; + xen-slim = xenPackages.xen-slim; + xen-light = xenPackages.xen-light; + + xen_4_8 = xenPackages.xen_4_8-vanilla; + xen_4_8-slim = xenPackages.xen_4_8-slim; + xen_4_8-light = xenPackages.xen_4_8-light; + xen_4_10 = xenPackages.xen_4_10-vanilla; + xen_4_10-slim = xenPackages.xen_4_10-slim; + xen_4_10-light = xenPackages.xen_4_10-light; + + xkbset = callPackage ../tools/X11/xkbset { }; + + xkbmon = callPackage ../applications/misc/xkbmon { }; + + win-spice = callPackage ../applications/virtualization/driver/win-spice { }; + win-virtio = callPackage ../applications/virtualization/driver/win-virtio { }; + win-qemu = callPackage ../applications/virtualization/driver/win-qemu { }; + win-pvdrivers = callPackage ../applications/virtualization/driver/win-pvdrivers { }; + win-signed-gplpv-drivers = callPackage ../applications/virtualization/driver/win-signed-gplpv-drivers { }; + + xfe = callPackage ../applications/misc/xfe { + fox = fox_1_6; + }; + + xfig = callPackage ../applications/graphics/xfig { }; + + xfractint = callPackage ../applications/graphics/xfractint {}; + + xineUI = callPackage ../applications/video/xine-ui { }; + + xmind = callPackage ../applications/misc/xmind { }; + + xneur = callPackage ../applications/misc/xneur { + enchant = enchant1; + }; + + gxneur = callPackage ../applications/misc/gxneur { + inherit (gnome2) libglade GConf; + }; + + xiphos = callPackage ../applications/misc/xiphos { + gconf = gnome2.GConf; + inherit (gnome2) libglade scrollkeeper; + gtkhtml = gnome2.gtkhtml4; + python = python27; + enchant = enchant1; + }; + + xournal = callPackage ../applications/graphics/xournal { + inherit (gnome2) libgnomeprint libgnomeprintui libgnomecanvas; + }; + + xournalpp = callPackage ../applications/graphics/xournalpp { + lua = lua5_3; + }; + + apvlv = callPackage ../applications/misc/apvlv { }; + + xpdf = libsForQt5.callPackage ../applications/misc/xpdf { }; + + xpointerbarrier = callPackage ../tools/X11/xpointerbarrier {}; + + xkb-switch = callPackage ../tools/X11/xkb-switch { }; + + xkblayout-state = callPackage ../applications/misc/xkblayout-state { }; + + xmobar = haskellPackages.xmobar; + + xmonad-log = callPackage ../tools/misc/xmonad-log { }; + + xmonad-with-packages = callPackage ../applications/window-managers/xmonad/wrapper.nix { + inherit (haskellPackages) ghcWithPackages; + packages = self: [ haskellPackages.xmonad-contrib ]; + }; + + xmonad_log_applet = callPackage ../applications/window-managers/xmonad/log-applet { + inherit (xfce) libxfce4util xfce4-panel; + }; + + xmonad_log_applet_mate = xmonad_log_applet.override { + desktopSupport = "mate"; + }; + + xmonad_log_applet_xfce = xmonad_log_applet.override { + desktopSupport = "xfce4"; + }; + + xmpp-client = callPackage ../applications/networking/instant-messengers/xmpp-client { }; + + libxpdf = callPackage ../applications/misc/xpdf/libxpdf.nix { }; + + xpra = callPackage ../tools/X11/xpra { }; + libfakeXinerama = callPackage ../tools/X11/xpra/libfakeXinerama.nix { }; + + xrectsel = callPackage ../tools/X11/xrectsel { }; + + xrestop = callPackage ../tools/X11/xrestop { }; + + xsd = callPackage ../development/libraries/xsd { }; + + xscope = callPackage ../applications/misc/xscope { }; + + xscreensaver = callPackage ../misc/screensavers/xscreensaver { + inherit (gnome2) libglade; + }; + + xsuspender = callPackage ../applications/misc/xsuspender { }; + + xss-lock = callPackage ../misc/screensavers/xss-lock { }; + + xloadimage = callPackage ../tools/X11/xloadimage { }; + + xssproxy = callPackage ../misc/screensavers/xssproxy { }; + + xsynth_dssi = callPackage ../applications/audio/xsynth-dssi { }; + + xterm = callPackage ../applications/misc/xterm { }; + + mlterm = callPackage ../applications/misc/mlterm { + libssh2 = null; + openssl = null; + }; + + roxterm = callPackage ../applications/misc/roxterm { }; + + termonad-with-packages = callPackage ../applications/misc/termonad { + inherit (haskellPackages) ghcWithPackages; + }; + + xtrace = callPackage ../tools/X11/xtrace { }; + + xtruss = callPackage ../tools/X11/xtruss { }; + + xmacro = callPackage ../tools/X11/xmacro { }; + + xmlcopyeditor = callPackage ../applications/editors/xmlcopyeditor { }; + + xmp = callPackage ../applications/audio/xmp { }; + + xnee = callPackage ../tools/X11/xnee { }; + + xvidcap = callPackage ../applications/video/xvidcap { + inherit (gnome2) scrollkeeper libglade; + }; + + xygrib = libsForQt5.callPackage ../applications/misc/xygrib/default.nix {}; + + xzgv = callPackage ../applications/graphics/xzgv { }; + + yabar = callPackage ../applications/window-managers/yabar { }; + + yabar-unstable = callPackage ../applications/window-managers/yabar/unstable.nix { }; + + yakuake = libsForQt5.callPackage ../applications/misc/yakuake { + inherit (kdeApplications) konsole; + }; + + yarp = callPackage ../applications/science/robotics/yarp {}; + + yarssr = callPackage ../applications/misc/yarssr { }; + + yate = callPackage ../applications/misc/yate { }; + + ydiff = callPackage ../development/tools/ydiff { }; + + yed = callPackage ../applications/graphics/yed {}; + + inherit (gnome3) yelp; + + yokadi = python3Packages.callPackage ../applications/misc/yokadi {}; + + yoshimi = callPackage ../applications/audio/yoshimi { }; + + youtube-dl = with python3Packages; toPythonApplication youtube-dl; + + youtube-dl-light = with python3Packages; toPythonApplication youtube-dl-light; + + youtube-viewer = perlPackages.WWWYoutubeViewer; + + ytcc = callPackage ../tools/networking/ytcc { }; + + zam-plugins = callPackage ../applications/audio/zam-plugins { }; + + zanshin = libsForQt5.callPackage ../applications/office/zanshin { + inherit (kdeApplications) akonadi-calendar akonadi-notes akonadi-search kidentitymanagement kontactinterface kldap; + inherit (kdeFrameworks) krunner kwallet; + boost = boost160; + }; + + zathura = callPackage ../applications/misc/zathura { }; + + zeroc_ice = callPackage ../development/libraries/zeroc-ice { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + zeronet = callPackage ../applications/networking/p2p/zeronet { }; + + zexy = callPackage ../applications/audio/pd-plugins/zexy { }; + + zgrviewer = callPackage ../applications/graphics/zgrviewer {}; + + zgv = callPackage ../applications/graphics/zgv { + # Enable the below line for terminal display. Note + # that it requires sixel graphics compatible terminals like mlterm + # or xterm -ti 340 + SDL = SDL_sixel; + }; + + zim = callPackage ../applications/office/zim { }; + + zita-njbridge = callPackage ../applications/audio/zita-njbridge { }; + + zola = callPackage ../applications/misc/zola { + inherit (darwin.apple_sdk.frameworks) CoreServices; + }; + + zoom-us = libsForQt59.callPackage ../applications/networking/instant-messengers/zoom-us { }; + + zotero = callPackage ../applications/office/zotero { }; + + zscroll = callPackage ../applications/misc/zscroll {}; + + zynaddsubfx = callPackage ../applications/audio/zynaddsubfx { }; + + ### GAMES + + _2048-in-terminal = callPackage ../games/2048-in-terminal { }; + + _20kly = callPackage ../games/20kly { }; + + _90secondportraits = callPackage ../games/90secondportraits { love = love_0_10; }; + + abbaye-des-morts = callPackage ../games/abbaye-des-morts { }; + + adom = callPackage ../games/adom { }; + + airstrike = callPackage ../games/airstrike { }; + + alienarena = callPackage ../games/alienarena { }; + + amoeba = callPackage ../games/amoeba { }; + amoeba-data = callPackage ../games/amoeba/data.nix { }; + + andyetitmoves = if stdenv.isLinux then callPackage ../games/andyetitmoves {} else null; + + angband = callPackage ../games/angband { }; + + anki = python3Packages.callPackage ../games/anki { + inherit (darwin.apple_sdk.frameworks) CoreAudio; + }; + + armagetronad = callPackage ../games/armagetronad { }; + + arena = callPackage ../games/arena {}; + + arx-libertatis = callPackage ../games/arx-libertatis { + stdenv = gcc6Stdenv; + }; + + asc = callPackage ../games/asc { + lua = lua5_1; + libsigcxx = libsigcxx12; + physfs = physfs_2; + }; + + assaultcube = callPackage ../games/assaultcube { }; + + astromenace = callPackage ../games/astromenace { }; + + atanks = callPackage ../games/atanks {}; + + azimuth = callPackage ../games/azimuth {}; + + ballAndPaddle = callPackage ../games/ball-and-paddle { + guile = guile_1_8; + }; + + banner = callPackage ../games/banner {}; + + bastet = callPackage ../games/bastet {}; + + beancount = with python3.pkgs; toPythonApplication beancount; + + bean-add = callPackage ../applications/office/beancount/bean-add.nix { }; + + bench = haskell.lib.justStaticExecutables haskellPackages.bench; + + beret = callPackage ../games/beret { }; + + bitsnbots = callPackage ../games/bitsnbots { + lua = lua5; + }; + + blackshades = callPackage ../games/blackshades { }; + + blobby = callPackage ../games/blobby { }; + + boohu = callPackage ../games/boohu { }; + + braincurses = callPackage ../games/braincurses { }; + + brogue = callPackage ../games/brogue { }; + + bsdgames = callPackage ../games/bsdgames { }; + + btanks = callPackage ../games/btanks { }; + + bzflag = callPackage ../games/bzflag { + inherit (darwin.apple_sdk.frameworks) Carbon CoreServices; + }; + + cataclysm-dda = callPackage ../games/cataclysm-dda { + inherit (darwin.apple_sdk.frameworks) CoreFoundation Cocoa; + }; + + cataclysm-dda-git = callPackage ../games/cataclysm-dda/git.nix { + inherit (darwin.apple_sdk.frameworks) CoreFoundation Cocoa; + }; + + chessdb = callPackage ../games/chessdb { }; + + chessx = libsForQt59.callPackage ../games/chessx { }; + + chocolateDoom = callPackage ../games/chocolate-doom { }; + + crispyDoom = callPackage ../games/crispy-doom { }; + + cri-o = callPackage ../applications/virtualization/cri-o {}; + + ckan = callPackage ../games/ckan { }; + + cockatrice = libsForQt5.callPackage ../games/cockatrice { }; + + commandergenius = callPackage ../games/commandergenius { }; + + confd = callPackage ../tools/system/confd { }; + + conmon = callPackage ../applications/virtualization/conmon { }; + + construoBase = lowPrio (callPackage ../games/construo { + libGL = null; + freeglut = null; + }); + + construo = construoBase.override { + inherit freeglut; + libGL = libGLU_combined; + }; + + crack_attack = callPackage ../games/crack-attack { }; + + crafty = callPackage ../games/crafty { }; + + crawlTiles = callPackage ../games/crawl { + tileMode = true; + }; + + crawl = callPackage ../games/crawl { }; + + crrcsim = callPackage ../games/crrcsim {}; + + curseofwar = callPackage ../games/curseofwar { SDL = null; }; + curseofwar-sdl = callPackage ../games/curseofwar { ncurses = null; }; + + cutemaze = libsForQt5.callPackage ../games/cutemaze {}; + + cuyo = callPackage ../games/cuyo { }; + + devilutionx = callPackage ../games/devilutionx {}; + + dhewm3 = callPackage ../games/dhewm3 {}; + + digikam = libsForQt5.callPackage ../applications/graphics/digikam { + inherit (plasma5) oxygen; + inherit (kdeApplications) akonadi-contacts kcalcore; + ffmpeg = ffmpeg_4; + opencv3 = opencv3WithoutCuda; + }; + + displaycal = (newScope pythonPackages) ../applications/graphics/displaycal {}; + + drumkv1 = callPackage ../applications/audio/drumkv1 { }; + + duckmarines = callPackage ../games/duckmarines { love = love_0_10; }; + + dwarf-fortress-packages = recurseIntoAttrs (callPackage ../games/dwarf-fortress { }); + + dwarf-fortress = dwarf-fortress-packages.dwarf-fortress; + + dwarf-therapist = dwarf-fortress-packages.dwarf-therapist; + + dxx-rebirth = callPackage ../games/dxx-rebirth { + physfs = physfs_2; + }; + + inherit (callPackages ../games/dxx-rebirth/assets.nix { }) + descent1-assets + descent2-assets; + + inherit (callPackages ../games/dxx-rebirth/full.nix { }) + d1x-rebirth-full + d2x-rebirth-full; + + easyrpg-player = callPackage ../games/easyrpg-player { }; + + eboard = callPackage ../games/eboard { }; + + eduke32 = callPackage ../games/eduke32 { }; + + egoboo = callPackage ../games/egoboo { }; + + EmptyEpsilon = callPackage ../games/empty-epsilon { }; + + endgame-singularity = callPackage ../games/endgame-singularity { }; + + endless-sky = callPackage ../games/endless-sky { }; + + enyo-doom = libsForQt5.callPackage ../games/enyo-doom { }; + + eternity = callPackage ../games/eternity-engine { }; + + eureka-editor = callPackage ../applications/misc/eureka-editor { }; + + extremetuxracer = callPackage ../games/extremetuxracer { + libpng = libpng12; + }; + + exult = callPackage ../games/exult { }; + + fltrator = callPackage ../games/fltrator { }; + + factorio = callPackage ../games/factorio { releaseType = "alpha"; }; + + factorio-experimental = factorio.override { releaseType = "alpha"; experimental = true; }; + + factorio-headless = factorio.override { releaseType = "headless"; }; + + factorio-headless-experimental = factorio.override { releaseType = "headless"; experimental = true; }; + + factorio-demo = factorio.override { releaseType = "demo"; }; + + factorio-mods = callPackage ../games/factorio/mods.nix { }; + + factorio-utils = callPackage ../games/factorio/utils.nix { }; + + fairymax = callPackage ../games/fairymax {}; + + fava = callPackage ../applications/office/fava {}; + + fish-fillets-ng = callPackage ../games/fish-fillets-ng {}; + + flightgear = libsForQt5.callPackage ../games/flightgear { }; + + flock = callPackage ../development/tools/flock { }; + + freecell-solver = callPackage ../games/freecell-solver { }; + + freeciv = callPackage ../games/freeciv { }; + + freeciv_gtk = freeciv.override { + gtkClient = true; + sdlClient = false; + }; + + freeciv_qt = freeciv.override { + qtClient = true; + sdlClient = false; + }; + + freedink = callPackage ../games/freedink { }; + + freeorion = callPackage ../games/freeorion { }; + + freesweep = callPackage ../games/freesweep { }; + + frotz = callPackage ../games/frotz { }; + + frogatto = callPackage ../games/frogatto { }; + + fsg = callPackage ../games/fsg { + wxGTK = wxGTK28.override { unicode = false; }; + }; + + galaxis = callPackage ../games/galaxis { }; + + gambatte = callPackage ../games/gambatte { }; + + garden-of-coloured-lights = callPackage ../games/garden-of-coloured-lights { allegro = allegro4; }; + + gargoyle = callPackage ../games/gargoyle { + inherit (darwin) cctools; + }; + + gav = callPackage ../games/gav { }; + + gcs = callPackage ../games/gcs { }; + + gcompris = libsForQt5.callPackage ../games/gcompris { }; + + gemrb = callPackage ../games/gemrb { }; + + gl117 = callPackage ../games/gl-117 {}; + + globulation2 = callPackage ../games/globulation { + boost = boost155; + }; + + gltron = callPackage ../games/gltron { }; + + gmad = callPackage ../games/gmad { }; + + gnubg = callPackage ../games/gnubg { }; + + gnuchess = callPackage ../games/gnuchess { }; + + gnugo = callPackage ../games/gnugo { }; + + gnujump = callPackage ../games/gnujump { }; + + gnushogi = callPackage ../games/gnushogi { }; + + gogui = callPackage ../games/gogui {}; + + gscrabble = python3Packages.callPackage ../games/gscrabble {}; + + gshogi = python3Packages.callPackage ../games/gshogi {}; + + gtetrinet = callPackage ../games/gtetrinet { + inherit (gnome2) GConf libgnome libgnomeui; + }; + + gtypist = callPackage ../games/gtypist { }; + + gzdoom = callPackage ../games/gzdoom { }; + + harmonist = callPackage ../games/harmonist { }; + + hawkthorne = callPackage ../games/hawkthorne { love = love_0_9; }; + + hedgewars = callPackage ../games/hedgewars { + inherit (haskellPackages) ghcWithPackages; + ffmpeg = ffmpeg_2; + }; + + hexen = callPackage ../games/hexen { }; + + holdingnuts = callPackage ../games/holdingnuts { }; + + hyperrogue = callPackage ../games/hyperrogue { }; + + icbm3d = callPackage ../games/icbm3d { }; + + ingen = callPackage ../applications/audio/ingen { + inherit (pythonPackages) rdflib; + }; + + ideogram = callPackage ../applications/graphics/ideogram { }; + + instead = callPackage ../games/instead { + lua = lua5; + }; + + instead-launcher = callPackage ../games/instead-launcher { }; + + ivan = callPackage ../games/ivan { }; + + ja2-stracciatella = callPackage ../games/ja2-stracciatella { }; + + klavaro = callPackage ../games/klavaro {}; + + kobodeluxe = callPackage ../games/kobodeluxe { }; + + leela-zero = libsForQt5.callPackage ../games/leela-zero { }; + + lgogdownloader = callPackage ../games/lgogdownloader { }; + + liberal-crime-squad = callPackage ../games/liberal-crime-squad { }; + + lincity = callPackage ../games/lincity {}; + + lincity_ng = callPackage ../games/lincity/ng.nix { + # https://github.com/lincity-ng/lincity-ng/issues/25 + physfs = physfs_2; + }; + + liquidwar = callPackage ../games/liquidwar { + guile = guile_2_0; + }; + + liquidwar5 = callPackage ../games/liquidwar/5.nix { + }; + + lugaru = callPackage ../games/lugaru {}; + + macopix = callPackage ../games/macopix { + gtk = gtk2; + }; + + mars = callPackage ../games/mars { }; + + megaglest = callPackage ../games/megaglest {}; + + minecraft = callPackage ../games/minecraft { }; + + minecraft-server = callPackage ../games/minecraft-server { }; + + moon-buggy = callPackage ../games/moon-buggy {}; + + multimc = libsForQt5.callPackage ../games/multimc { }; + + inherit (callPackages ../games/minetest { }) + minetestclient_4 minetestserver_4 + minetestclient_5 minetestserver_5; + + minetest = minetestclient_5; + + mnemosyne = callPackage ../games/mnemosyne { + python = python3; + }; + + mrrescue = callPackage ../games/mrrescue { }; + + mudlet = libsForQt5.callPackage ../games/mudlet { + inherit (lua51Packages) luafilesystem lrexlib-pcre luazip luasql-sqlite3; + }; + + n2048 = callPackage ../games/n2048 {}; + + naev = callPackage ../games/naev { }; + + nethack = callPackage ../games/nethack { }; + + nethack-qt = callPackage ../games/nethack { + qtMode = true; + stdenv = gccStdenv; + }; + + nethack-x11 = callPackage ../games/nethack { x11Mode = true; }; + + neverball = callPackage ../games/neverball { }; + + nexuiz = callPackage ../games/nexuiz { }; + + njam = callPackage ../games/njam { }; + + newtonwars = callPackage ../games/newtonwars { }; + + nxengine-evo = callPackage ../games/nxengine-evo { }; + + odamex = callPackage ../games/odamex { }; + + oilrush = callPackage ../games/oilrush { }; + + onscripter-en = callPackage ../games/onscripter-en { }; + + openarena = callPackage ../games/openarena { }; + + opendungeons = callPackage ../games/opendungeons { + ogre = ogre1_9; + }; + + openlierox = callPackage ../games/openlierox { }; + + openclonk = callPackage ../games/openclonk { }; + + openjk = callPackage ../games/openjk { }; + + openmw = libsForQt5.callPackage ../games/openmw { }; + + openmw-tes3mp = libsForQt5.callPackage ../games/openmw/tes3mp.nix { }; + + openraPackages = import ../games/openra pkgs; + + openra = openraPackages.engines.release; + + openrw = callPackage ../games/openrw { }; + + openspades = callPackage ../games/openspades { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + + openttd = callPackage ../games/openttd { + zlib = zlib.override { + static = true; + }; + }; + + opentyrian = callPackage ../games/opentyrian { }; + + openxcom = callPackage ../games/openxcom { }; + + orthorobot = callPackage ../games/orthorobot { }; + + pacvim = callPackage ../games/pacvim { }; + + performous = callPackage ../games/performous { + boost = boost166; + }; + + pingus = callPackage ../games/pingus {}; + + pioneer = callPackage ../games/pioneer { }; + + pioneers = callPackage ../games/pioneers { }; + + planetary_annihilation = callPackage ../games/planetaryannihilation { }; + + pong3d = callPackage ../games/pong3d { }; + + pokerth = libsForQt5.callPackage ../games/pokerth { }; + + pokerth-server = libsForQt5.callPackage ../games/pokerth { target = "server"; }; + + prboom = callPackage ../games/prboom { }; + + privateer = callPackage ../games/privateer { }; + + pysolfc = callPackage ../games/pysolfc { }; + + qweechat = callPackage ../applications/networking/irc/qweechat { }; + + qqwing = callPackage ../games/qqwing { }; + + quake3wrapper = callPackage ../games/quake3/wrapper { }; + + quake3demo = quake3wrapper { + name = "quake3-demo-${lib.getVersion quake3demodata}"; + description = "Demo of Quake 3 Arena, a classic first-person shooter"; + paks = [ quake3pointrelease quake3demodata ]; + }; + + quake3demodata = callPackage ../games/quake3/content/demo.nix { }; + + quake3pointrelease = callPackage ../games/quake3/content/pointrelease.nix { }; + + quakespasm = callPackage ../games/quakespasm { }; + vkquake = callPackage ../games/quakespasm/vulkan.nix { }; + + ioquake3 = callPackage ../games/quake3/ioquake { }; + + quantumminigolf = callPackage ../games/quantumminigolf {}; + + racer = callPackage ../games/racer { }; + + redeclipse = callPackage ../games/redeclipse { }; + + residualvm = callPackage ../games/residualvm { }; + + rftg = callPackage ../games/rftg { }; + + rigsofrods = callPackage ../games/rigsofrods { + angelscript = angelscript_2_22; + ogre = ogre1_9; + ogrepaged = ogrepaged.override { + ogre = ogre1_9; + }; + mygui = mygui.override { + withOgre = true; + }; + }; + + riko4 = callPackage ../games/riko4 { }; + + rili = callPackage ../games/rili { }; + + rimshot = callPackage ../games/rimshot { love = love_0_7; }; + + rogue = callPackage ../games/rogue { + ncurses = ncurses5; + }; + + robotfindskitten = callPackage ../games/robotfindskitten { }; + + rocksndiamonds = callPackage ../games/rocksndiamonds { }; + + rrootage = callPackage ../games/rrootage { }; + + saga = callPackage ../applications/gis/saga { + inherit (darwin.apple_sdk.frameworks) Cocoa; + }; + + samplv1 = callPackage ../applications/audio/samplv1 { }; + + sauerbraten = callPackage ../games/sauerbraten {}; + + scaleway-cli = callPackage ../tools/admin/scaleway-cli { }; + + scid = callPackage ../games/scid { + tcl = tcl-8_5; + tk = tk-8_5; + }; + + scid-vs-pc = callPackage ../games/scid-vs-pc { + tcl = tcl-8_6; + tk = tk-8_6; + }; + + scummvm = callPackage ../games/scummvm { }; + + inherit (callPackage ../games/scummvm/games.nix { }) + beneath-a-steel-sky + drascula-the-vampire-strikes-back + flight-of-the-amazon-queen + lure-of-the-temptress; + + scorched3d = callPackage ../games/scorched3d { }; + + scrolls = callPackage ../games/scrolls { }; + + sdlmame = callPackage ../games/sdlmame { }; + + service-wrapper = callPackage ../os-specific/linux/service-wrapper { }; + + sgtpuzzles = callPackage (callPackage ../games/sgt-puzzles) { }; + + sienna = callPackage ../games/sienna { love = love_0_10; }; + + sil = callPackage ../games/sil { }; + + simutrans = callPackage ../games/simutrans { }; + # get binaries without data built by Hydra + simutrans_binaries = lowPrio simutrans.binaries; + + snake4 = callPackage ../games/snake4 { }; + + soi = callPackage ../games/soi { + lua = lua5_1; + }; + + solarus = libsForQt5.callPackage ../games/solarus { }; + + solarus-quest-editor = libsForQt5.callPackage ../development/tools/solarus-quest-editor { }; + + # You still can override by passing more arguments. + space-orbit = callPackage ../games/space-orbit { }; + + spring = callPackage ../games/spring { + boost = boost155; + cmake = cmake_2_8; + }; + + springLobby = callPackage ../games/spring/springlobby.nix { }; + + ssl-cert-check = callPackage ../tools/admin/ssl-cert-check { }; + + stardust = callPackage ../games/stardust {}; + + stockfish = callPackage ../games/stockfish { }; + + steamPackages = dontRecurseIntoAttrs (callPackage ../games/steam { }); + + steam = steamPackages.steam-chrootenv; + + steam-run = steam.run; + steam-run-native = (steam.override { + nativeOnly = true; + }).run; + + steamcmd = steamPackages.steamcmd; + + linux-steam-integration = callPackage ../games/linux-steam-integration { + gtk = pkgs.gtk3; + }; + + protontricks = callPackage ../tools/package-management/protontricks { + inherit (python3Packages) buildPythonApplication vdf; + inherit (gnome3) zenity; + wine = wineWowPackages.minimal; + }; + + stepmania = callPackage ../games/stepmania { + ffmpeg = ffmpeg_2; + }; + + stuntrally = callPackage ../games/stuntrally { + ogre = ogre1_9; + mygui = mygui.override { + withOgre = true; + }; + }; + + superTux = callPackage ../games/supertux { }; + + superTuxKart = callPackage ../games/super-tux-kart { }; + + synthv1 = callPackage ../applications/audio/synthv1 { }; + + t4kcommon = callPackage ../games/t4kcommon { }; + + tcl2048 = callPackage ../games/tcl2048 { }; + + the-powder-toy = callPackage ../games/the-powder-toy { + lua = lua5_1; + }; + + tbe = callPackage ../games/the-butterfly-effect { }; + + teetertorture = callPackage ../games/teetertorture { }; + + teeworlds = callPackage ../games/teeworlds { }; + + tengine = callPackage ../servers/http/tengine { + modules = with nginxModules; [ rtmp dav moreheaders modsecurity-nginx ]; + }; + + tennix = callPackage ../games/tennix { }; + + terraria-server = callPackage ../games/terraria-server { }; + + tibia = pkgsi686Linux.callPackage ../games/tibia { }; + + tintin = callPackage ../games/tintin { }; + + tinyfugue = callPackage ../games/tinyfugue { }; + + tome4 = callPackage ../games/tome4 { }; + + toppler = callPackage ../games/toppler { }; + + trackballs = callPackage ../games/trackballs { }; + + tremulous = callPackage ../games/tremulous { }; + + tuxpaint = callPackage ../games/tuxpaint { }; + + tuxtype = callPackage ../games/tuxtype { }; + + speed_dreams = callPackage ../games/speed-dreams { + # Torcs wants to make shared libraries linked with plib libraries (it provides static). + # i686 is the only platform I know than can do that linking without plib built with -fPIC + libpng = libpng12; + }; + + torcs = callPackage ../games/torcs { }; + + trigger = callPackage ../games/trigger { }; + + typespeed = callPackage ../games/typespeed { }; + + ufoai = callPackage ../games/ufoai { }; + + ultimatestunts = callPackage ../games/ultimatestunts { }; + + ultrastar-creator = libsForQt5.callPackage ../tools/misc/ultrastar-creator { }; + + ultrastar-manager = libsForQt5.callPackage ../tools/misc/ultrastar-manager { }; + + ultrastardx = callPackage ../games/ultrastardx { + ffmpeg = ffmpeg_2; + }; + + unnethack = callPackage ../games/unnethack { }; + + uqm = callPackage ../games/uqm { }; + + urbanterror = callPackage ../games/urbanterror { }; + + ue4 = callPackage ../games/ue4 { }; + + ue4demos = recurseIntoAttrs (callPackage ../games/ue4demos { }); + + ut2004Packages = dontRecurseIntoAttrs (callPackage ../games/ut2004 { }); + + ut2004demo = res.ut2004Packages.ut2004 [ res.ut2004Packages.ut2004-demo ]; + + vapor = callPackage ../games/vapor { love = love_0_8; }; + + vapoursynth = callPackage ../development/libraries/vapoursynth { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + }; + + vapoursynth-editor = libsForQt5.callPackage ../development/libraries/vapoursynth/editor.nix { }; + + vapoursynth-mvtools = callPackage ../development/libraries/vapoursynth-mvtools { }; + + vassal = callPackage ../games/vassal { }; + + vdrift = callPackage ../games/vdrift { }; + + # To ensure vdrift's code is built on hydra + vdrift-bin = vdrift.bin; + + vectoroids = callPackage ../games/vectoroids { }; + + vessel = pkgsi686Linux.callPackage ../games/vessel { }; + + vitetris = callPackage ../games/vitetris { }; + + vms-empire = callPackage ../games/vms-empire { }; + + voxelands = callPackage ../games/voxelands { + libpng = libpng12; + }; + + warmux = callPackage ../games/warmux { }; + + warsow-engine = callPackage ../games/warsow/engine.nix { }; + + warsow = callPackage ../games/warsow { }; + + warzone2100 = libsForQt5.callPackage ../games/warzone2100 { }; + + wesnoth = callPackage ../games/wesnoth { + inherit (darwin.apple_sdk.frameworks) Cocoa Foundation; + }; + + wesnoth-dev = wesnoth; + + widelands = callPackage ../games/widelands { + lua = lua5_2; + }; + + worldofgoo_demo = worldofgoo.override { + demo = true; + }; + + worldofgoo = callPackage ../games/worldofgoo { }; + + xboard = callPackage ../games/xboard { }; + + xbomb = callPackage ../games/xbomb { }; + + xconq = callPackage ../games/xconq { + tcl = tcl-8_5; + tk = tk-8_5; + }; + + xjump = callPackage ../games/xjump { }; + # TODO: the corresponding nix file is missing + # xracer = callPackage ../games/xracer { }; + + xmoto = callPackage ../games/xmoto { }; + + xonotic = callPackage ../games/xonotic { }; + + xpilot-ng = callPackage ../games/xpilot { }; + bloodspilot-server = callPackage ../games/xpilot/bloodspilot-server.nix {}; + bloodspilot-client = callPackage ../games/xpilot/bloodspilot-client.nix {}; + + xskat = callPackage ../games/xskat { }; + + xsnow = callPackage ../games/xsnow { }; + + xsok = callPackage ../games/xsok { }; + + xsokoban = callPackage ../games/xsokoban { }; + + xtris = callPackage ../games/xtris { }; + + inherit (callPackage ../games/quake2/yquake2 { + inherit (darwin.apple_sdk.frameworks) Cocoa OpenAL; + }) + yquake2 + yquake2-ctf + yquake2-ground-zero + yquake2-the-reckoning + yquake2-all-games; + + zandronum = callPackage ../games/zandronum { }; + + zandronum-server = zandronum.override { + serverOnly = true; + }; + + zangband = callPackage ../games/zangband { }; + + zaz = callPackage ../games/zaz { }; + + zdbsp = callPackage ../games/zdoom/zdbsp.nix { }; + + zdoom = callPackage ../games/zdoom { }; + + zod = callPackage ../games/zod { }; + + zoom = callPackage ../games/zoom { }; + + keen4 = callPackage ../games/keen4 { }; + + zeroadPackages = dontRecurseIntoAttrs (callPackage ../games/0ad { + wxGTK = wxGTK30; + }); + + zeroad = zeroadPackages.zeroad; + + ### DESKTOP ENVIRONMENTS + + clearlooks-phenix = callPackage ../misc/themes/clearlooks-phenix { }; + + deepin = recurseIntoAttrs (import ../desktops/deepin { + inherit pkgs libsForQt5; + inherit (lib) makeScope; + }); + + enlightenment = recurseIntoAttrs (callPackage ../desktops/enlightenment { + callPackage = newScope pkgs.enlightenment; + }); + + gnome2 = recurseIntoAttrs (callPackage ../desktops/gnome-2 { }); + + gnome3 = recurseIntoAttrs (callPackage ../desktops/gnome-3 { }); + + gnomeExtensions = recurseIntoAttrs { + appindicator = callPackage ../desktops/gnome-3/extensions/appindicator { }; + battery-status = callPackage ../desktops/gnome-3/extensions/battery-status { }; + caffeine = callPackage ../desktops/gnome-3/extensions/caffeine { }; + clipboard-indicator = callPackage ../desktops/gnome-3/extensions/clipboard-indicator { }; + dash-to-dock = callPackage ../desktops/gnome-3/extensions/dash-to-dock { }; + dash-to-panel = callPackage ../desktops/gnome-3/extensions/dash-to-panel { }; + gsconnect = callPackage ../desktops/gnome-3/extensions/gsconnect { }; + icon-hider = callPackage ../desktops/gnome-3/extensions/icon-hider { }; + impatience = callPackage ../desktops/gnome-3/extensions/impatience.nix { }; + mediaplayer = callPackage ../desktops/gnome-3/extensions/mediaplayer { }; + nohotcorner = callPackage ../desktops/gnome-3/extensions/nohotcorner { }; + no-title-bar = callPackage ../desktops/gnome-3/extensions/no-title-bar { }; + pidgin-im-integration = callPackage ../desktops/gnome-3/extensions/pidgin-im-integration { }; + remove-dropdown-arrows = callPackage ../desktops/gnome-3/extensions/remove-dropdown-arrows { }; + sound-output-device-chooser = callPackage ../desktops/gnome-3/extensions/sound-output-device-chooser { }; + system-monitor = callPackage ../desktops/gnome-3/extensions/system-monitor { }; + taskwhisperer = callPackage ../desktops/gnome-3/extensions/taskwhisperer { }; + tilingnome = callPackage ../desktops/gnome-3/extensions/tilingnome { }; + timepp = callPackage ../desktops/gnome-3/extensions/timepp { }; + topicons-plus = callPackage ../desktops/gnome-3/extensions/topicons-plus { }; + window-corner-preview = callPackage ../desktops/gnome-3/extensions/window-corner-preview { }; + }; + + hsetroot = callPackage ../tools/X11/hsetroot { }; + + imwheel = callPackage ../tools/X11/imwheel { }; + + kakasi = callPackage ../tools/text/kakasi { }; + + lumina = recurseIntoAttrs (callPackage ../desktops/lumina { }); + + lxqt = recurseIntoAttrs (import ../desktops/lxqt { + inherit pkgs libsForQt5; + inherit (lib) makeScope; + }); + + mate = recurseIntoAttrs (callPackage ../desktops/mate { }); + + pantheon = recurseIntoAttrs (callPackage ../desktops/pantheon { }); + + maxx = callPackage ../desktops/maxx { }; + + plasma-applet-volumewin7mixer = libsForQt5.callPackage ../applications/misc/plasma-applet-volumewin7mixer { }; + + redshift = callPackage ../applications/misc/redshift { + inherit (python3Packages) python pygobject3 pyxdg wrapPython; + inherit (darwin.apple_sdk.frameworks) CoreLocation ApplicationServices Foundation Cocoa; + geoclue = geoclue2; + }; + + redshift-plasma-applet = libsForQt5.callPackage ../applications/misc/redshift-plasma-applet { }; + + latte-dock = libsForQt5.callPackage ../applications/misc/latte-dock { }; + + adwaita-qt = libsForQt5.callPackage ../misc/themes/adwaita-qt { }; + + orion = callPackage ../misc/themes/orion {}; + + albatross = callPackage ../misc/themes/albatross { }; + + gtk_engines = callPackage ../misc/themes/gtk2/gtk-engines { }; + + gtk-engine-bluecurve = callPackage ../misc/themes/gtk2/gtk-engine-bluecurve { }; + + gtk-engine-murrine = callPackage ../misc/themes/gtk2/gtk-engine-murrine { }; + + gnome-themes-extra = gnome3.gnome-themes-extra; + + numix-gtk-theme = callPackage ../misc/themes/numix { }; + + numix-solarized-gtk-theme = callPackage ../misc/themes/numix-solarized { }; + + numix-sx-gtk-theme = callPackage ../misc/themes/numix-sx { }; + + onestepback = callPackage ../misc/themes/onestepback { }; + + theme-jade1 = callPackage ../misc/themes/jade1 { }; + + theme-obsidian2 = callPackage ../misc/themes/obsidian2 { }; + + theme-vertex = callPackage ../misc/themes/vertex { }; + + rox-filer = callPackage ../desktops/rox/rox-filer { + gtk = gtk2; + }; + + solarc-gtk-theme = callPackage ../misc/themes/solarc { }; + + xfce = xfce4-12; + xfceUnstable = xfce4-14; + + xfce4-12 = recurseIntoAttrs (callPackage ../desktops/xfce { }); + xfce4-14 = recurseIntoAttrs (callPackage ../desktops/xfce4-14 { }); + + xrandr-invert-colors = callPackage ../applications/misc/xrandr-invert-colors { }; + + ### DESKTOP ENVIRONMENTS / PLASMA 5 + + plasma5 = + let + mkPlasma5 = import ../desktops/plasma-5; + attrs = { + inherit libsForQt5 lib fetchurl; + gconf = gnome2.GConf; + inherit gsettings-desktop-schemas; + }; + in + recurseIntoAttrs (makeOverridable mkPlasma5 attrs); + + inherit (kdeFrameworks) kded kinit frameworkintegration; + + inherit (plasma5) + bluedevil breeze-gtk breeze-qt5 breeze-grub breeze-plymouth discover + kactivitymanagerd kde-cli-tools kde-gtk-config kdeplasma-addons kgamma5 + kinfocenter kmenuedit kscreen kscreenlocker ksshaskpass ksysguard + kwallet-pam kwayland-integration kwin kwrited milou oxygen plasma-browser-integration + plasma-desktop plasma-integration plasma-nm plasma-pa plasma-vault plasma-workspace + plasma-workspace-wallpapers polkit-kde-agent powerdevil sddm-kcm + systemsettings user-manager xdg-desktop-portal-kde; + + ### SCIENCE + + ### SCIENCE/CHEMISTY + + avogadro = callPackage ../applications/science/chemistry/avogadro { + eigen = eigen2; + }; + + gwyddion = callPackage ../applications/science/chemistry/gwyddion {}; + + jmol = callPackage ../applications/science/chemistry/jmol { }; + + marvin = callPackage ../applications/science/chemistry/marvin { }; + + molden = callPackage ../applications/science/chemistry/molden { }; + + octopus = callPackage ../applications/science/chemistry/octopus { openblas=openblasCompat; }; + + openmolcas = callPackage ../applications/science/chemistry/openmolcas { }; + + pymol = callPackage ../applications/science/chemistry/pymol { }; + + quantum-espresso = callPackage ../applications/science/chemistry/quantum-espresso { }; + + quantum-espresso-mpi = callPackage ../applications/science/chemistry/quantum-espresso { + mpi = openmpi; + }; + + siesta = callPackage ../applications/science/chemistry/siesta { }; + + siesta-mpi = callPackage ../applications/science/chemistry/siesta { + mpi = openmpi; + }; + + ### SCIENCE/GEOMETRY + + drgeo = callPackage ../applications/science/geometry/drgeo { + inherit (gnome2) libglade; + guile = guile_1_8; + }; + + tetgen = callPackage ../applications/science/geometry/tetgen { }; # AGPL3+ + tetgen_1_4 = callPackage ../applications/science/geometry/tetgen/1.4.nix { }; # MIT + + ### SCIENCE/BENCHMARK + + papi = callPackage ../development/libraries/science/benchmark/papi { }; + + ### SCIENCE/BIOLOGY + + alliance = callPackage ../applications/science/electronics/alliance { }; + + ants = callPackage ../applications/science/biology/ants { }; + + aragorn = callPackage ../applications/science/biology/aragorn { }; + + archimedes = callPackage ../applications/science/electronics/archimedes { + stdenv = gcc49Stdenv; + }; + + bedtools = callPackage ../applications/science/biology/bedtools { }; + + bcftools = callPackage ../applications/science/biology/bcftools { }; + + bftools = callPackage ../applications/science/biology/bftools { }; + + cd-hit = callPackage ../applications/science/biology/cd-hit { }; + + cmtk = callPackage ../applications/science/biology/cmtk { }; + + clustal-omega = callPackage ../applications/science/biology/clustal-omega { }; + + conglomerate = callPackage ../applications/science/biology/conglomerate { }; + + dcm2niix = callPackage ../applications/science/biology/dcm2niix { }; + + diamond = callPackage ../applications/science/biology/diamond { }; + + ecopcr = callPackage ../applications/science/biology/ecopcr { }; + + eggnog-mapper = callPackage ../applications/science/biology/eggnog-mapper { }; + + emboss = callPackage ../applications/science/biology/emboss { }; + + est-sfs = callPackage ../applications/science/biology/est-sfs { }; + + ezminc = callPackage ../applications/science/biology/EZminc { }; + + exonerate = callPackage ../applications/science/biology/exonerate { }; + + hisat2 = callPackage ../applications/science/biology/hisat2 { }; + + htslib = callPackage ../development/libraries/science/biology/htslib { }; + + igv = callPackage ../applications/science/biology/igv { }; + + inormalize = callPackage ../applications/science/biology/inormalize { }; + + itsx = callPackage ../applications/science/biology/itsx { }; + + iv = callPackage ../applications/science/biology/iv { + neuron-version = neuron.version; + }; + + kallisto = callPackage ../applications/science/biology/kallisto { }; + + migrate = callPackage ../applications/science/biology/migrate { }; + + mirtk = callPackage ../development/libraries/science/biology/mirtk { }; + + muscle = callPackage ../applications/science/biology/muscle { }; + + n3 = callPackage ../applications/science/biology/N3 { }; + + neuron = callPackage ../applications/science/biology/neuron { + python = null; + }; + + neuron-mpi = appendToName "mpi" (neuron.override { + mpi = pkgs.openmpi; + }); + + neuron-full = neuron-mpi.override { inherit python; }; + + mrbayes = callPackage ../applications/science/biology/mrbayes { }; + + megahit = callPackage ../applications/science/biology/megahit { }; + + messer-slim = callPackage ../applications/science/biology/messer-slim { }; + + minc_tools = callPackage ../applications/science/biology/minc-tools { }; + + minc_widgets = callPackage ../applications/science/biology/minc-widgets { }; + + mni_autoreg = callPackage ../applications/science/biology/mni_autoreg { }; + + minimap2 = callPackage ../applications/science/biology/minimap2 { }; + + mosdepth = callPackage ../applications/science/biology/mosdepth { }; + + ncbi_tools = callPackage ../applications/science/biology/ncbi-tools { }; + + niftyreg = callPackage ../applications/science/biology/niftyreg { }; + + niftyseg = callPackage ../applications/science/biology/niftyseg { }; + + octopus-caller = callPackage ../applications/science/biology/octopus { }; + + paml = callPackage ../applications/science/biology/paml { }; + + picard-tools = callPackage ../applications/science/biology/picard-tools { }; + + platypus = callPackage ../applications/science/biology/platypus { }; + + plink = callPackage ../applications/science/biology/plink { }; + + plink-ng = callPackage ../applications/science/biology/plink-ng { }; + + prodigal = callPackage ../applications/science/biology/prodigal { }; + + raxml = callPackage ../applications/science/biology/raxml { }; + + raxml-mpi = appendToName "mpi" (raxml.override { + mpi = true; + }); + + samtools = callPackage ../applications/science/biology/samtools { }; + samtools_0_1_19 = callPackage ../applications/science/biology/samtools/samtools_0_1_19.nix { + stdenv = gccStdenv; + }; + + snpeff = callPackage ../applications/science/biology/snpeff { }; + + somatic-sniper = callPackage ../applications/science/biology/somatic-sniper { }; + + stacks = callPackage ../applications/science/biology/stacks { }; + + star = callPackage ../applications/science/biology/star { }; + + strelka = callPackage ../applications/science/biology/strelka { }; + + inherit (callPackages ../applications/science/biology/sumatools {}) + sumalibs + sumaclust + sumatra; + + seaview = callPackage ../applications/science/biology/seaview { }; + + varscan = callPackage ../applications/science/biology/varscan { }; + + hmmer = callPackage ../applications/science/biology/hmmer { }; + + bwa = callPackage ../applications/science/biology/bwa { }; + + ### SCIENCE/MACHINE LEARNING + + sc2-headless = callPackage ../applications/science/machine-learning/sc2-headless { }; + + ### SCIENCE/MATH + + almonds = callPackage ../applications/science/math/almonds { }; + + arpack = callPackage ../development/libraries/science/math/arpack { }; + + blas = callPackage ../development/libraries/science/math/blas { }; + + brial = callPackage ../development/libraries/science/math/brial { }; + + clblas = callPackage ../development/libraries/science/math/clblas { + inherit (darwin.apple_sdk.frameworks) Accelerate CoreGraphics CoreVideo OpenCL; + }; + + cliquer = callPackage ../development/libraries/science/math/cliquer { }; + + ecos = callPackage ../development/libraries/science/math/ecos { }; + + flintqs = callPackage ../development/libraries/science/math/flintqs { }; + + getdp = callPackage ../applications/science/math/getdp { }; + + gurobi = callPackage ../applications/science/math/gurobi { }; + + jags = callPackage ../applications/science/math/jags { }; + + libbraiding = callPackage ../development/libraries/science/math/libbraiding { }; + + libhomfly = callPackage ../development/libraries/science/math/libhomfly { }; + + liblapack = callPackage ../development/libraries/science/math/liblapack {}; + + liblbfgs = callPackage ../development/libraries/science/math/liblbfgs { }; + + lrs = callPackage ../development/libraries/science/math/lrs { }; + + m4ri = callPackage ../development/libraries/science/math/m4ri { }; + + m4rie = callPackage ../development/libraries/science/math/m4rie { }; + + mkl = callPackage ../development/libraries/science/math/mkl { }; + + nasc = callPackage ../applications/science/math/nasc { }; + + openblas = callPackage ../development/libraries/science/math/openblas { }; + + # A version of OpenBLAS using 32-bit integers on all platforms for compatibility with + # standard BLAS and LAPACK. + openblasCompat = openblas.override { blas64 = false; }; + + openlibm = callPackage ../development/libraries/science/math/openlibm {}; + + openspecfun = callPackage ../development/libraries/science/math/openspecfun {}; + + planarity = callPackage ../development/libraries/science/math/planarity { }; + + scalapack = callPackage ../development/libraries/science/math/scalapack { + mpi = openmpi; + }; + + rankwidth = callPackage ../development/libraries/science/math/rankwidth { }; + + fenics = callPackage ../development/libraries/science/math/fenics { + inherit (python3Packages) numpy ply pytest python six sympy; + pythonPackages = python3Packages; + pythonBindings = true; + docs = true; + }; + + lcalc = callPackage ../development/libraries/science/math/lcalc { }; + + lrcalc = callPackage ../applications/science/math/lrcalc { }; + + lie = callPackage ../applications/science/math/LiE { }; + + magma = callPackage ../development/libraries/science/math/magma { }; + + mathematica = callPackage ../applications/science/math/mathematica { }; + mathematica9 = callPackage ../applications/science/math/mathematica/9.nix { }; + mathematica10 = callPackage ../applications/science/math/mathematica/10.nix { }; + mathematica11 = callPackage ../applications/science/math/mathematica/11.nix { }; + + metis = callPackage ../development/libraries/science/math/metis {}; + + nauty = callPackage ../applications/science/math/nauty {}; + + osi = callPackage ../development/libraries/science/math/osi { }; + + or-tools = callPackage ../development/libraries/science/math/or-tools { + pythonProtobuf = pythonPackages.protobuf; + }; + + rubiks = callPackage ../development/libraries/science/math/rubiks { }; + + petsc = callPackage ../development/libraries/science/math/petsc { }; + + parmetis = callPackage ../development/libraries/science/math/parmetis { + mpi = openmpi; + }; + + QuadProgpp = callPackage ../development/libraries/science/math/QuadProgpp { }; + + scs = callPackage ../development/libraries/science/math/scs { }; + + sage = callPackage ../applications/science/math/sage { }; + sageWithDoc = sage.override { withDoc = true; }; + + suitesparse_4_2 = callPackage ../development/libraries/science/math/suitesparse/4.2.nix { }; + suitesparse_4_4 = callPackage ../development/libraries/science/math/suitesparse/4.4.nix {}; + suitesparse_5_3 = callPackage ../development/libraries/science/math/suitesparse {}; + suitesparse = suitesparse_5_3; + + superlu = callPackage ../development/libraries/science/math/superlu {}; + + symmetrica = callPackage ../applications/science/math/symmetrica {}; + + sympow = callPackage ../development/libraries/science/math/sympow { }; + + ipopt = callPackage ../development/libraries/science/math/ipopt { openblas = openblasCompat; }; + + gmsh = callPackage ../applications/science/math/gmsh { }; + + zn_poly = callPackage ../development/libraries/science/math/zn_poly { }; + + ### SCIENCE/MOLECULAR-DYNAMICS + + dl-poly-classic-mpi = callPackage ../applications/science/molecular-dynamics/dl-poly-classic { + mpi = openmpi; + }; + + lammps = callPackage ../applications/science/molecular-dynamics/lammps { + fftw = fftw; + }; + + lammps-mpi = lowPrio (lammps.override { + mpi = openmpi; + }); + + gromacs = callPackage ../applications/science/molecular-dynamics/gromacs { + singlePrec = true; + mpiEnabled = false; + fftw = fftwSinglePrec; + cmake = cmakeCurses; + }; + + gromacsMpi = lowPrio (gromacs.override { + singlePrec = true; + mpiEnabled = true; + fftw = fftwSinglePrec; + cmake = cmakeCurses; + }); + + gromacsDouble = lowPrio (gromacs.override { + singlePrec = false; + mpiEnabled = false; + fftw = fftw; + cmake = cmakeCurses; + }); + + gromacsDoubleMpi = lowPrio (gromacs.override { + singlePrec = false; + mpiEnabled = true; + fftw = fftw; + cmake = cmakeCurses; + }); + + ### SCIENCE/MEDICINE + + aliza = callPackage ../applications/science/medicine/aliza { }; + + ### PHYSICS + + sacrifice = callPackage ../applications/science/physics/sacrifice {}; + + sherpa = callPackage ../applications/science/physics/sherpa {}; + + xfitter = callPackage ../applications/science/physics/xfitter {}; + + ### SCIENCE/PROGRAMMING + + dafny = dotnetPackages.Dafny; + + groove = callPackage ../applications/science/programming/groove { }; + + plm = callPackage ../applications/science/programming/plm { }; + + scyther = callPackage ../applications/science/programming/scyther { }; + + ### SCIENCE/LOGIC + + abc-verifier = callPackage ../applications/science/logic/abc {}; + + abella = callPackage ../applications/science/logic/abella {}; + + acgtk = callPackage ../applications/science/logic/acgtk {}; + + alt-ergo = callPackage ../applications/science/logic/alt-ergo {}; + + aspino = callPackage ../applications/science/logic/aspino {}; + + beluga = callPackage ../applications/science/logic/beluga { }; + + boogie = dotnetPackages.Boogie; + + inherit (callPackage ./coq-packages.nix { + inherit (ocaml-ng) ocamlPackages_4_05; + }) mkCoqPackages + coqPackages_8_5 coq_8_5 + coqPackages_8_6 coq_8_6 + coqPackages_8_7 coq_8_7 + coqPackages_8_8 coq_8_8 + coqPackages_8_9 coq_8_9 + coqPackages_8_10 coq_8_10 + coqPackages coq + ; + + coq2html = callPackage ../applications/science/logic/coq2html { }; + + cryptoverif = callPackage ../applications/science/logic/cryptoverif { }; + + caprice32 = callPackage ../misc/emulators/caprice32 { }; + + cubicle = callPackage ../applications/science/logic/cubicle { + ocamlPackages = ocaml-ng.ocamlPackages_4_05; + }; + + cvc3 = callPackage ../applications/science/logic/cvc3 { + gmp = lib.overrideDerivation gmp (a: { dontDisableStatic = true; }); + }; + cvc4 = callPackage ../applications/science/logic/cvc4 {}; + + drat-trim = callPackage ../applications/science/logic/drat-trim {}; + + ekrhyper = callPackage ../applications/science/logic/ekrhyper { + inherit (ocaml-ng.ocamlPackages_4_02) ocaml; + }; + + eprover = callPackage ../applications/science/logic/eprover { }; + + gappa = callPackage ../applications/science/logic/gappa { }; + + gfan = callPackage ../applications/science/math/gfan {}; + + giac = callPackage ../applications/science/math/giac { }; + giac-with-xcas = giac.override { enableGUI = true; }; + + ginac = callPackage ../applications/science/math/ginac { }; + + glom = callPackage ../applications/misc/glom { }; + + glucose = callPackage ../applications/science/logic/glucose { }; + glucose-syrup = callPackage ../applications/science/logic/glucose/syrup.nix { }; + + hol = callPackage ../applications/science/logic/hol { }; + + inherit (ocamlPackages) hol_light; + + hologram = callPackage ../tools/security/hologram { }; + + tini = callPackage ../applications/virtualization/tini {}; + + ifstat-legacy = callPackage ../tools/networking/ifstat-legacy { }; + + isabelle = callPackage ../applications/science/logic/isabelle { + polyml = stdenv.lib.overrideDerivation polyml57 (attrs: { + configureFlags = [ "--enable-intinf-as-int" "--with-gmp" "--disable-shared" ]; + }); + + java = if stdenv.isLinux then jre else jdk; + }; + + iprover = callPackage ../applications/science/logic/iprover { }; + + jonprl = callPackage ../applications/science/logic/jonprl { + smlnj = if stdenv.isDarwin + then smlnjBootstrap + else smlnj; + }; + + lean = callPackage ../applications/science/logic/lean {}; + lean2 = callPackage ../applications/science/logic/lean2 {}; + lean3 = lean; + elan = callPackage ../applications/science/logic/elan {}; + + leo2 = callPackage ../applications/science/logic/leo2 { + ocaml = ocaml-ng.ocamlPackages_4_01_0.ocaml;}; + + leo3-bin = callPackage ../applications/science/logic/leo3/binary.nix {}; + + logisim = callPackage ../applications/science/logic/logisim {}; + + ltl2ba = callPackage ../applications/science/logic/ltl2ba {}; + + metis-prover = callPackage ../applications/science/logic/metis-prover { }; + + mcrl2 = callPackage ../applications/science/logic/mcrl2 { }; + + minisat = callPackage ../applications/science/logic/minisat {}; + minisatUnstable = callPackage ../applications/science/logic/minisat/unstable.nix {}; + + monosat = callPackage ../applications/science/logic/monosat {}; + + opensmt = callPackage ../applications/science/logic/opensmt { }; + + ott = callPackage ../applications/science/logic/ott { }; + + otter = callPackage ../applications/science/logic/otter {}; + + picosat = callPackage ../applications/science/logic/picosat {}; + + libpoly = callPackage ../applications/science/logic/poly {}; + + prooftree = callPackage ../applications/science/logic/prooftree {}; + + prover9 = callPackage ../applications/science/logic/prover9 { }; + + proverif = callPackage ../applications/science/logic/proverif { }; + + satallax = callPackage ../applications/science/logic/satallax { + ocaml = ocaml-ng.ocamlPackages_4_01_0.ocaml; + }; + + saw-tools = callPackage ../applications/science/logic/saw-tools {}; + + spass = callPackage ../applications/science/logic/spass { + stdenv = gccStdenv; + }; + + statverif = callPackage ../applications/science/logic/statverif { + inherit (ocaml-ng.ocamlPackages_4_05) ocaml; + }; + + tptp = callPackage ../applications/science/logic/tptp {}; + + celf = callPackage ../applications/science/logic/celf { + smlnj = if stdenv.isDarwin + then smlnjBootstrap + else smlnj; + }; + + fast-downward = callPackage ../applications/science/logic/fast-downward { }; + + twelf = callPackage ../applications/science/logic/twelf { + smlnj = if stdenv.isDarwin + then smlnjBootstrap + else smlnj; + }; + + verifast = callPackage ../applications/science/logic/verifast {}; + + veriT = callPackage ../applications/science/logic/verit {}; + + why3 = callPackage ../applications/science/logic/why3 { }; + + workcraft = callPackage ../applications/science/logic/workcraft {}; + + yices = callPackage ../applications/science/logic/yices { + gmp-static = gmp.override { withStatic = true; }; + }; + + z3 = callPackage ../applications/science/logic/z3 { python = python2; }; + z3-tptp = callPackage ../applications/science/logic/z3/tptp.nix {}; + + tlaplus = callPackage ../applications/science/logic/tlaplus {}; + tlaps = callPackage ../applications/science/logic/tlaplus/tlaps.nix { + inherit (ocaml-ng.ocamlPackages_4_05) ocaml; + }; + tlaplusToolbox = callPackage ../applications/science/logic/tlaplus/toolbox.nix {gtk = gtk2;}; + + aiger = callPackage ../applications/science/logic/aiger {}; + + avy = callPackage ../applications/science/logic/avy {}; + + btor2tools = callPackage ../applications/science/logic/btor2tools {}; + + boolector = callPackage ../applications/science/logic/boolector {}; + + symbiyosys = callPackage ../applications/science/logic/symbiyosys {}; + + lingeling = callPackage ../applications/science/logic/lingeling {}; + + ### SCIENCE / ELECTRONICS + + adms = callPackage ../applications/science/electronics/adms { }; + + # Since version 8 Eagle requires an Autodesk account and a subscription + # in contrast to single payment for the charged editions. + # This is the last version with the old model. + eagle7 = callPackage ../applications/science/electronics/eagle/eagle7.nix { }; + + eagle = libsForQt5.callPackage ../applications/science/electronics/eagle/eagle.nix { }; + + caneda = libsForQt5.callPackage ../applications/science/electronics/caneda { }; + + geda = callPackage ../applications/science/electronics/geda { + guile = guile_2_0; + }; + + gerbv = callPackage ../applications/science/electronics/gerbv { }; + + gtkwave = callPackage ../applications/science/electronics/gtkwave { }; + + fped = callPackage ../applications/science/electronics/fped { }; + + kicad = callPackage ../applications/science/electronics/kicad { + wxGTK = wxGTK30; + boost = boost160; + }; + kicad-with-packages3d = kicad.overrideAttrs (old: { modules = old.modules ++ [ old.passthru.packages3d ]; }); + + kicad-unstable = python.pkgs.callPackage ../applications/science/electronics/kicad/unstable.nix { + wxGTK = wxGTK30; + boost = boost160; + }; + + librepcb = libsForQt5.callPackage ../applications/science/electronics/librepcb { }; + + ngspice = callPackage ../applications/science/electronics/ngspice { }; + + pcb = callPackage ../applications/science/electronics/pcb { }; + + qucs = callPackage ../applications/science/electronics/qucs { }; + + xcircuit = callPackage ../applications/science/electronics/xcircuit { }; + + xoscope = callPackage ../applications/science/electronics/xoscope { }; + + + ### SCIENCE / MATH + + caffe = callPackage ../applications/science/math/caffe ({ + opencv3 = opencv3WithoutCuda; # Used only for image loading. + inherit (darwin.apple_sdk.frameworks) Accelerate CoreGraphics CoreVideo; + } // (config.caffe or {})); + + caffe2 = callPackage ../development/libraries/science/math/caffe2 (rec { + inherit (python36Packages) python future six numpy pydot; + protobuf = protobuf3_1; + python-protobuf = python36Packages.protobuf.override { inherit protobuf; }; + opencv3 = opencv3WithoutCuda; # Used only for image loading. + }); + + caffeine-ng = callPackage ../tools/X11/caffeine-ng {}; + + cntk = callPackage ../applications/science/math/cntk { + inherit (linuxPackages) nvidia_x11; + opencv3 = opencv3WithoutCuda; # Used only for image loading. + }; + + ecm = callPackage ../applications/science/math/ecm { }; + + eukleides = callPackage ../applications/science/math/eukleides { + texLive = texlive.combine { inherit (texlive) scheme-small; }; + texinfo = texinfo4; + }; + + form = callPackage ../applications/science/math/form { }; + + fricas = callPackage ../applications/science/math/fricas { }; + + gap = callPackage ../applications/science/math/gap { }; + + gap-minimal = lowPrio (gap.override { packageSet = "minimal"; }); + + gap-full = lowPrio (gap.override { packageSet = "full"; }); + + geogebra = callPackage ../applications/science/math/geogebra { }; + + maxima = callPackage ../applications/science/math/maxima { + ecl = null; + }; + maxima-ecl = maxima.override { + ecl = ecl_16_1_2; + ecl-fasl = true; + sbcl = null; + }; + + mxnet = callPackage ../applications/science/math/mxnet { + inherit (linuxPackages) nvidia_x11; + }; + + wxmaxima = callPackage ../applications/science/math/wxmaxima { wxGTK = wxGTK30; }; + + pari = callPackage ../applications/science/math/pari { tex = texlive.combined.scheme-basic; }; + gp2c = callPackage ../applications/science/math/pari/gp2c.nix { }; + + palp = callPackage ../applications/science/math/palp { }; + + ratpoints = callPackage ../applications/science/math/ratpoints {}; + + calc = callPackage ../applications/science/math/calc { }; + + pcalc = callPackage ../applications/science/math/pcalc { }; + + bcal = callPackage ../applications/science/math/bcal { }; + + pspp = callPackage ../applications/science/math/pspp { }; + + pynac = callPackage ../applications/science/math/pynac { }; + + singular = callPackage ../applications/science/math/singular { }; + + scilab = callPackage ../applications/science/math/scilab { }; + + scilab-bin = callPackage ../applications/science/math/scilab-bin {}; + + scotch = callPackage ../applications/science/math/scotch { }; + + mininet = callPackage ../tools/virtualization/mininet { }; + + msieve = callPackage ../applications/science/math/msieve { }; + + weka = callPackage ../applications/science/math/weka { }; + + yad = callPackage ../tools/misc/yad { }; + + yacas = callPackage ../applications/science/math/yacas { }; + + speedcrunch = libsForQt5.callPackage ../applications/science/math/speedcrunch { }; + + ### SCIENCE / MISC + + boinc = callPackage ../applications/science/misc/boinc { }; + + celestia = callPackage ../applications/science/astronomy/celestia { + lua = lua5_1; + inherit (pkgs.gnome2) gtkglext; + }; + + cytoscape = callPackage ../applications/science/misc/cytoscape { }; + + fityk = callPackage ../applications/science/misc/fityk { }; + + gildas = callPackage ../applications/science/astronomy/gildas { }; + + gplates = callPackage ../applications/science/misc/gplates { + boost = boost160; + cgal = cgal.override { boost = boost160; }; + }; + + gravit = callPackage ../applications/science/astronomy/gravit { }; + + golly = callPackage ../applications/science/misc/golly { wxGTK = wxGTK30; }; + golly-beta = callPackage ../applications/science/misc/golly/beta.nix { wxGTK = wxGTK30; }; + + megam = callPackage ../applications/science/misc/megam { }; + + netlogo = callPackage ../applications/science/misc/netlogo { }; + + ns-3 = callPackage ../development/libraries/science/networking/ns3 { }; + + root = callPackage ../applications/science/misc/root { + inherit (darwin.apple_sdk.frameworks) Cocoa OpenGL; + stdenv = if stdenv.cc.isClang then llvmPackages_5.stdenv else stdenv; + }; + + root5 = lowPrio (callPackage ../applications/science/misc/root/5.nix { + inherit (darwin.apple_sdk.frameworks) Cocoa OpenGL; + stdenv = if stdenv.cc.isClang then llvmPackages_5.stdenv else stdenv; + }); + + rink = callPackage ../applications/science/misc/rink { }; + + simgrid = callPackage ../applications/science/misc/simgrid { }; + + spyder = with python3.pkgs; toPythonApplication spyder; + + openspace = callPackage ../applications/science/astronomy/openspace { }; + + stellarium = libsForQt5.callPackage ../applications/science/astronomy/stellarium { }; + + astrolabe-generator = callPackage ../applications/science/astronomy/astrolabe-generator { }; + + tulip = callPackage ../applications/science/misc/tulip { + cmake = cmake_2_8; + }; + + vite = callPackage ../applications/science/misc/vite { }; + + xearth = callPackage ../applications/science/astronomy/xearth { }; + xplanet = callPackage ../applications/science/astronomy/xplanet { }; + + ### SCIENCE / PHYSICS + + apfelgrid = callPackage ../development/libraries/physics/apfelgrid { }; + + apfel = callPackage ../development/libraries/physics/apfel { }; + + applgrid = callPackage ../development/libraries/physics/applgrid { }; + + hoppet = callPackage ../development/libraries/physics/hoppet { }; + + fastjet = callPackage ../development/libraries/physics/fastjet { }; + + fastnlo = callPackage ../development/libraries/physics/fastnlo { }; + + geant4 = libsForQt5.callPackage ../development/libraries/physics/geant4 { }; + + cernlib = callPackage ../development/libraries/physics/cernlib { }; + + g4py = callPackage ../development/libraries/physics/geant4/g4py { }; + + hepmc2 = callPackage ../development/libraries/physics/hepmc2 { }; + + hepmc3 = callPackage ../development/libraries/physics/hepmc3 { }; + + herwig = callPackage ../development/libraries/physics/herwig { }; + + lhapdf = callPackage ../development/libraries/physics/lhapdf { }; + + mcgrid = callPackage ../development/libraries/physics/mcgrid { }; + + mela = callPackage ../development/libraries/physics/mela { }; + + nlojet = callPackage ../development/libraries/physics/nlojet { }; + + pythia = callPackage ../development/libraries/physics/pythia { }; + + rivet = callPackage ../development/libraries/physics/rivet { + imagemagick = graphicsmagick-imagemagick-compat; + }; + + thepeg = callPackage ../development/libraries/physics/thepeg { }; + + yoda = callPackage ../development/libraries/physics/yoda { }; + yoda-with-root = lowPrio (yoda.override { + withRootSupport = true; + }); + + qcdnum = callPackage ../development/libraries/physics/qcdnum { }; + + ### SCIENCE/ROBOTICS + + apmplanner2 = libsForQt5.callPackage ../applications/science/robotics/apmplanner2 { }; + + betaflight-configurator = callPackage ../applications/science/robotics/betaflight-configurator { }; + + ### MISC + + acpilight = callPackage ../misc/acpilight { }; + + android-file-transfer = libsForQt5.callPackage ../tools/filesystems/android-file-transfer { }; + + antimicro = libsForQt5.callPackage ../tools/misc/antimicro { }; + + atari800 = callPackage ../misc/emulators/atari800 { }; + + ataripp = callPackage ../misc/emulators/atari++ { }; + + auctex = callPackage ../tools/typesetting/tex/auctex { }; + + areca = callPackage ../applications/backup/areca { }; + + attract-mode = callPackage ../misc/emulators/attract-mode { }; + + beep = callPackage ../misc/beep { }; + + bees = callPackage ../tools/filesystems/bees { }; + + blackbird = callPackage ../misc/themes/blackbird { }; + + bootil = callPackage ../development/libraries/bootil { }; + + brgenml1lpr = pkgsi686Linux.callPackage ../misc/cups/drivers/brgenml1lpr {}; + + brgenml1cupswrapper = callPackage ../misc/cups/drivers/brgenml1cupswrapper {}; + + brightnessctl = callPackage ../misc/brightnessctl { }; + + calaos_installer = libsForQt5.callPackage ../misc/calaos/installer {}; + + ccemux = callPackage ../misc/emulators/ccemux { }; + + click = callPackage ../applications/networking/cluster/click { }; + + clinfo = callPackage ../tools/system/clinfo { }; + + cups = callPackage ../misc/cups { + libusb = libusb1; + }; + + cups-filters = callPackage ../misc/cups/filters.nix { }; + + cups-pk-helper = callPackage ../misc/cups/cups-pk-helper.nix { }; + + cups-kyocera = callPackage ../misc/cups/drivers/kyocera {}; + + cups-kyodialog3 = callPackage ../misc/cups/drivers/kyodialog3 {}; + + cups-dymo = callPackage ../misc/cups/drivers/dymo {}; + + cups-toshiba-estudio = callPackage ../misc/cups/drivers/estudio {}; + + cups-zj-58 = callPackage ../misc/cups/drivers/zj-58 { }; + + crashplan = callPackage ../applications/backup/crashplan { }; + crashplansb = callPackage ../applications/backup/crashplan/crashplan-small-business.nix { gconf = gnome2.GConf; }; + + colort = callPackage ../applications/misc/colort { }; + + terminal-parrot = callPackage ../applications/misc/terminal-parrot { }; + + e17gtk = callPackage ../misc/themes/e17gtk { }; + + epson-alc1100 = callPackage ../misc/drivers/epson-alc1100 { }; + + epson-escpr = callPackage ../misc/drivers/epson-escpr { }; + epson-escpr2 = callPackage ../misc/drivers/epson-escpr2 { }; + + epson_201207w = callPackage ../misc/drivers/epson_201207w { }; + + epson-201106w = callPackage ../misc/drivers/epson-201106w { }; + + epson-workforce-635-nx625-series = callPackage ../misc/drivers/epson-workforce-635-nx625-series { }; + + gutenprint = callPackage ../misc/drivers/gutenprint { }; + + gutenprintBin = callPackage ../misc/drivers/gutenprint/bin.nix { }; + + cups-bjnp = callPackage ../misc/cups/drivers/cups-bjnp { }; + + cups-brother-hl1110 = pkgsi686Linux.callPackage ../misc/cups/drivers/hl1110 { }; + + cups-brother-hl3140cw = pkgsi686Linux.callPackage ../misc/cups/drivers/hl3140cw { }; + + cups-googlecloudprint = callPackage ../misc/cups/drivers/googlecloudprint { }; + + # this driver ships with pre-compiled 32-bit binary libraries + cnijfilter_2_80 = pkgsi686Linux.callPackage ../misc/cups/drivers/cnijfilter_2_80 { }; + + cnijfilter_4_00 = callPackage ../misc/cups/drivers/cnijfilter_4_00 { + libusb = libusb1; + }; + + cnijfilter2 = callPackage ../misc/cups/drivers/cnijfilter2 { + libusb = libusb1; + }; + + darcnes = callPackage ../misc/emulators/darcnes { }; + + darling-dmg = callPackage ../tools/filesystems/darling-dmg { }; + + desmume = callPackage ../misc/emulators/desmume { inherit (pkgs.gnome2) gtkglext libglade; }; + + dbacl = callPackage ../tools/misc/dbacl { }; + + dblatex = callPackage ../tools/typesetting/tex/dblatex { + enableAllFeatures = false; + }; + + dblatexFull = appendToName "full" (dblatex.override { + enableAllFeatures = true; + }); + + dbus-map = callPackage ../tools/misc/dbus-map { }; + + dell-530cdn = callPackage ../misc/drivers/dell-530cdn {}; + + dosbox = callPackage ../misc/emulators/dosbox { }; + + dpkg = callPackage ../tools/package-management/dpkg { }; + + ekiga = callPackage ../applications/networking/instant-messengers/ekiga { }; + + dumb = callPackage ../misc/dumb { }; + + emulationstation = callPackage ../misc/emulators/emulationstation { + stdenv = gcc5Stdenv; + }; + + electricsheep = callPackage ../misc/screensavers/electricsheep { }; + + equilux-theme = callPackage ../misc/themes/equilux-theme { }; + + flam3 = callPackage ../tools/graphics/flam3 { }; + + glee = callPackage ../tools/graphics/glee { }; + + fakenes = callPackage ../misc/emulators/fakenes { }; + + faust = res.faust2; + + faust1 = callPackage ../applications/audio/faust/faust1.nix { }; + + faust2 = callPackage ../applications/audio/faust/faust2.nix { + llvm = llvm_5; + }; + + faust2alqt = callPackage ../applications/audio/faust/faust2alqt.nix { }; + + faust2alsa = callPackage ../applications/audio/faust/faust2alsa.nix { }; + + faust2csound = callPackage ../applications/audio/faust/faust2csound.nix { }; + + faust2firefox = callPackage ../applications/audio/faust/faust2firefox.nix { }; + + faust2jack = callPackage ../applications/audio/faust/faust2jack.nix { }; + + faust2jaqt = callPackage ../applications/audio/faust/faust2jaqt.nix { }; + + faust2ladspa = callPackage ../applications/audio/faust/faust2ladspa.nix { }; + + faust2lv2 = callPackage ../applications/audio/faust/faust2lv2.nix { }; + + faustlive = callPackage ../applications/audio/faust/faustlive.nix { }; + + fceux = callPackage ../misc/emulators/fceux { }; + + flockit = callPackage ../tools/backup/flockit { }; + + foldingathome = callPackage ../misc/foldingathome { }; + + foo2zjs = callPackage ../misc/drivers/foo2zjs {}; + + foomatic-filters = callPackage ../misc/drivers/foomatic-filters {}; + + gajim = callPackage ../applications/networking/instant-messengers/gajim { + inherit (gst_all_1) gstreamer gst-plugins-base gst-libav gst-plugins-ugly; + }; + + gammu = callPackage ../applications/misc/gammu { }; + + gensgs = pkgsi686Linux.callPackage ../misc/emulators/gens-gs { }; + + ghostscript = callPackage ../misc/ghostscript { }; + + ghostscriptX = appendToName "with-X" (ghostscript.override { + cupsSupport = true; + x11Support = true; + }); + + glava = callPackage ../applications/misc/glava {}; + + gnome-breeze = callPackage ../misc/themes/gnome-breeze { }; + + gnuk = callPackage ../misc/gnuk { + gcc-arm-embedded = pkgsCross.arm-embedded.buildPackages.gcc; + binutils-arm-embedded = pkgsCross.arm-embedded.buildPackages.binutils; + }; + + guetzli = callPackage ../applications/graphics/guetzli { }; + + gummi = callPackage ../applications/misc/gummi { }; + + gxemul = callPackage ../misc/emulators/gxemul { }; + + hatari = callPackage ../misc/emulators/hatari { }; + + helm = callPackage ../applications/audio/helm { }; + + helmfile = callPackage ../applications/networking/cluster/helmfile { }; + + heptio-ark = callPackage ../applications/networking/cluster/heptio-ark { }; + + hplip = callPackage ../misc/drivers/hplip { }; + + hplipWithPlugin = hplip.override { withPlugin = true; }; + + hplip_3_16_11 = callPackage ../misc/drivers/hplip/3.16.11.nix { }; + + hplipWithPlugin_3_16_11 = hplip_3_16_11.override { withPlugin = true; }; + + hplip_3_18_5 = callPackage ../misc/drivers/hplip/3.18.5.nix { }; + + hplipWithPlugin_3_18_5 = hplip_3_18_5.override { withPlugin = true; }; + + hyperfine = callPackage ../tools/misc/hyperfine { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + websocat = callPackage ../tools/misc/websocat { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + epkowa = callPackage ../misc/drivers/epkowa { }; + + utsushi = callPackage ../misc/drivers/utsushi { }; + + idsk = callPackage ../tools/filesystems/idsk { }; + + igraph = callPackage ../development/libraries/igraph { }; + + igprof = callPackage ../development/tools/misc/igprof { }; + + illum = callPackage ../tools/system/illum { }; + + image_optim = callPackage ../applications/graphics/image_optim { inherit (nodePackages) svgo; }; + + # using the new configuration style proposal which is unstable + jack1 = callPackage ../misc/jackaudio/jack1.nix { }; + + jack2 = callPackage ../misc/jackaudio { + libopus = libopus.override { withCustomModes = true; }; + inherit (darwin.apple_sdk.frameworks) AudioUnit CoreAudio Accelerate; + inherit (darwin) libobjc; + }; + libjack2 = jack2.override { prefix = "lib"; }; + jack2Full = jack2; # TODO: move to aliases.nix + + keynav = callPackage ../tools/X11/keynav { }; + + kompose = callPackage ../applications/networking/cluster/kompose { }; + + kontemplate = callPackage ../applications/networking/cluster/kontemplate { }; + + inherit (callPackage ../applications/networking/cluster/kops {}) + mkKops + kops_1_12 + kops_1_13 + ; + kops = kops_1_13; + + lguf-brightness = callPackage ../misc/lguf-brightness { }; + + lilypond = callPackage ../misc/lilypond { guile = guile_1_8; }; + + lilypond-unstable = callPackage ../misc/lilypond/unstable.nix { }; + + lilypond-with-fonts = callPackage ../misc/lilypond/with-fonts.nix { + lilypond = lilypond-unstable; + }; + + openlilylib-fonts = callPackage ../misc/lilypond/fonts.nix { + lilypond = lilypond-unstable; + }; + + loop = callPackage ../tools/misc/loop { }; + + mailcore2 = callPackage ../development/libraries/mailcore2 { + icu = icu58; + }; + + martyr = callPackage ../development/libraries/martyr { }; + + mess = callPackage ../misc/emulators/mess { + inherit (pkgs.gnome2) GConf; + }; + + moltengamepad = callPackage ../misc/drivers/moltengamepad { }; + + openzwave = callPackage ../development/libraries/openzwave { }; + + mongoc = callPackage ../development/libraries/mongoc { }; + + morph = callPackage ../tools/package-management/morph { }; + + mupen64plus = callPackage ../misc/emulators/mupen64plus { }; + + muse = callPackage ../applications/audio/muse { }; + + musly = callPackage ../applications/audio/musly { }; + + mynewt-newt = callPackage ../tools/package-management/mynewt-newt { }; + + inherit (callPackage ../tools/package-management/nix { + storeDir = config.nix.storeDir or "/nix/store"; + stateDir = config.nix.stateDir or "/nix/var"; + boehmgc = boehmgc.override { enableLargeConfig = true; }; + }) + nix + nix1 + nixStable + nixUnstable + nixFlakes; + + nixops = callPackage ../tools/package-management/nixops { }; + + nixops_1_6_1 = callPackage ../tools/package-management/nixops/nixops-v1_6_1.nix {}; + + nixopsUnstable = lowPrio (callPackage ../tools/package-management/nixops/unstable.nix { }); + + nixops-dns = callPackage ../tools/package-management/nixops/nixops-dns.nix { }; + + /* Evaluate a NixOS configuration using this evaluation of Nixpkgs. + + With this function you can write, for example, a package that + depends on a custom virtual machine image. + + Parameter: A module, path or list of those that represent the + configuration of the NixOS system to be constructed. + + Result: An attribute set containing packages produced by this + evaluation of NixOS, such as toplevel, kernel and + initialRamdisk. + The result can be extended in the modules by defining + extra attributes in system.build. + + Example: + + let + myOS = pkgs.nixos ({ lib, pkgs, config, ... }: { + + config.services.nginx = { + enable = true; + # ... + }; + + # Use config.system.build to exports relevant parts of a + # configuration. The runner attribute should not be + # considered a fully general replacement for systemd + # functionality. + config.system.build.run-nginx = config.systemd.services.nginx.runner; + }); + in + myOS.run-nginx + + Unlike in plain NixOS, the nixpkgs.config and + nixpkgs.system options will be ignored by default. Instead, + nixpkgs.pkgs will have the default value of pkgs as it was + constructed right after invoking the nixpkgs function (e.g. the + value of import { overlays = [./my-overlay.nix]; } + but not the value of (import {} // { extra = ...; }). + + If you do want to use the config.nixpkgs options, you are + probably better off by calling nixos/lib/eval-config.nix + directly, even though it is possible to set config.nixpkgs.pkgs. + + For more information about writing NixOS modules, see + https://nixos.org/nixos/manual/index.html#sec-writing-modules + + Note that you will need to have called Nixpkgs with the system + parameter set to the right value for your deployment target. + */ + nixos = configuration: + (import (pkgs.path + "/nixos/lib/eval-config.nix") { + inherit (pkgs.stdenv.hostPlatform) system; + modules = [( + { lib, ... }: { + config.nixpkgs.pkgs = lib.mkDefault pkgs; + } + )] ++ ( + if builtins.isList configuration + then configuration + else [configuration] + ); + }).config.system.build; + + + /* + * Run a NixOS VM network test using this evaluation of Nixpkgs. + * + * It is mostly equivalent to `import ./make-test.nix` from the + * NixOS manual[1], except that your `pkgs` will be used instead of + * letting NixOS invoke Nixpkgs again. If a test machine needs to + * set NixOS options under `nixpkgs`, it must set only the + * `nixpkgs.pkgs` option. For the details, see the Nixpkgs + * `pkgs.nixos` documentation. + * + * Parameter: + * A NixOS VM test network, or path to it. Example: + * + * { lib, ... }: + * { name = "my-test"; + * nodes = { + * machine-1 = someNixOSConfiguration; + * machine-2 = ...; + * } + * } + * + * Result: + * A derivation that runs the VM test. + * + * [1]: For writing NixOS tests, see + * https://nixos.org/nixos/manual/index.html#sec-nixos-tests + */ + nixosTest = + let + /* The nixos/lib/testing.nix module, preapplied with arguments that + * make sense for this evaluation of Nixpkgs. + */ + nixosTesting = + (import ../../nixos/lib/testing.nix { + inherit (pkgs.stdenv.hostPlatform) system; + inherit pkgs; + extraConfigurations = [( + { lib, ... }: { + config.nixpkgs.pkgs = lib.mkDefault pkgs; + } + )]; + }); + in + test: + let + loadedTest = if builtins.typeOf test == "path" + then import test + else test; + calledTest = if pkgs.lib.isFunction loadedTest + then callPackage loadedTest {} + else loadedTest; + in + nixosTesting.makeTest calledTest; + + nixosOptionsDoc = attrs: + (import ../../nixos/lib/make-options-doc/default.nix) + ({ inherit pkgs lib; } // attrs); + + nixui = callPackage ../tools/package-management/nixui { node_webkit = nwjs_0_12; }; + + nixdoc = callPackage ../tools/nix/nixdoc {}; + + nix-bundle = callPackage ../tools/package-management/nix-bundle { }; + + nix-delegate = haskell.lib.justStaticExecutables haskellPackages.nix-delegate; + nix-deploy = haskell.lib.justStaticExecutables haskellPackages.nix-deploy; + nix-diff = haskell.lib.justStaticExecutables haskellPackages.nix-diff; + + nix-du = callPackage ../tools/package-management/nix-du { }; + + nix-info = callPackage ../tools/nix/info { }; + nix-info-tested = nix-info.override { doCheck = true; }; + + nix-index = callPackage ../tools/package-management/nix-index { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + nix-pin = callPackage ../tools/package-management/nix-pin { }; + + nix-prefetch = callPackage ../tools/package-management/nix-prefetch { }; + + nix-prefetch-github = callPackage ../build-support/nix-prefetch-github {}; + + inherit (callPackages ../tools/package-management/nix-prefetch-scripts { }) + nix-prefetch-bzr + nix-prefetch-cvs + nix-prefetch-git + nix-prefetch-hg + nix-prefetch-svn + nix-prefetch-scripts; + + nix-update-source = callPackage ../tools/package-management/nix-update-source {}; + + nix-script = callPackage ../tools/nix/nix-script {}; + + nix-template-rpm = callPackage ../build-support/templaterpm { inherit (pythonPackages) python toposort; }; + + nix-top = callPackage ../tools/package-management/nix-top { }; + + nix-universal-prefetch = callPackage ../tools/package-management/nix-universal-prefetch { }; + + nix-repl = throw ( + "nix-repl has been removed because it's not maintained anymore, " + + (lib.optionalString (! lib.versionAtLeast "2" (lib.versions.major builtins.nixVersion)) + "ugrade your Nix installation to a newer version and ") + + "use `nix repl` instead. " + + "Also see https://github.com/NixOS/nixpkgs/pull/44903" + ); + + nix-review = callPackage ../tools/package-management/nix-review { }; + + nix-serve = callPackage ../tools/package-management/nix-serve { }; + + nixpkgs-fmt = callPackage ../tools/nix/nixpkgs-fmt { }; + + nixos-artwork = callPackage ../data/misc/nixos-artwork { }; + nixos-icons = callPackage ../data/misc/nixos-artwork/icons.nix { }; + nixos-grub2-theme = callPackage ../data/misc/nixos-artwork/grub2-theme.nix { }; + + nixos-container = callPackage ../tools/virtualization/nixos-container { }; + + norwester-font = callPackage ../data/fonts/norwester {}; + + nut = callPackage ../applications/misc/nut { }; + + solfege = callPackage ../misc/solfege { }; + + disnix = callPackage ../tools/package-management/disnix { }; + + dysnomia = callPackage ../tools/package-management/disnix/dysnomia (config.disnix or {}); + + disnixos = callPackage ../tools/package-management/disnix/disnixos { }; + + DisnixWebService = callPackage ../tools/package-management/disnix/DisnixWebService { }; + + lkproof = callPackage ../tools/typesetting/tex/lkproof { }; + + lice = callPackage ../tools/misc/lice {}; + + m33-linux = callPackage ../misc/drivers/m33-linux { }; + + mnemonicode = callPackage ../misc/mnemonicode { }; + + mysql-workbench = callPackage ../applications/misc/mysql-workbench (let mysql = mysql57; in { + gdal = gdal.override {mysql = mysql // {lib = {dev = mysql;};};}; + mysql = mysql; + pcre = pcre-cpp; + }); + + redis-desktop-manager = libsForQt5.callPackage ../applications/misc/redis-desktop-manager { }; + + robin-map = callPackage ../development/libraries/robin-map { }; + + robo3t = callPackage ../applications/misc/robo3t { }; + + rucksack = callPackage ../development/tools/rucksack { }; + + sam-ba = callPackage ../tools/misc/sam-ba { }; + + sndio = callPackage ../misc/sndio { }; + + # Oclgrind 18.3 does not work with newer LLVMs (but HEAD does, so + # fix this after next release). + oclgrind = callPackage ../development/tools/analysis/oclgrind { llvmPackages = llvmPackages_6; }; + + opkg = callPackage ../tools/package-management/opkg { }; + + opkg-utils = callPackage ../tools/package-management/opkg-utils { }; + + pgmanage = callPackage ../applications/misc/pgmanage { }; + + pgadmin = callPackage ../applications/misc/pgadmin { }; + + pgf = pgf2; + + # Keep the old PGF since some documents don't render properly with + # the new one. + pgf1 = callPackage ../tools/typesetting/tex/pgf/1.x.nix { }; + + pgf2 = callPackage ../tools/typesetting/tex/pgf/2.x.nix { }; + + pgf3 = callPackage ../tools/typesetting/tex/pgf/3.x.nix { }; + + pgfplots = callPackage ../tools/typesetting/tex/pgfplots { }; + + physlock = callPackage ../misc/screensavers/physlock { }; + + pjsip = callPackage ../applications/networking/pjsip { }; + + ppsspp = libsForQt5.callPackage ../misc/emulators/ppsspp { }; + + pt = callPackage ../applications/misc/pt { }; + + protocol = python3Packages.callPackage ../applications/networking/protocol { }; + + pykms = callPackage ../tools/networking/pykms { }; + + pyload = callPackage ../applications/networking/pyload {}; + + uae = callPackage ../misc/emulators/uae { }; + + fsuae = callPackage ../misc/emulators/fs-uae { }; + + putty = callPackage ../applications/networking/remote/putty { + gtk2 = gtk2-x11; + }; + + qMasterPassword = libsForQt5.callPackage ../applications/misc/qMasterPassword { }; + + redprl = callPackage ../applications/science/logic/redprl { }; + + retroarchBare = callPackage ../misc/emulators/retroarch { + inherit (darwin) libobjc; + inherit (darwin.apple_sdk.frameworks) AppKit Foundation; + }; + + retroarch = wrapRetroArch { retroarch = retroarchBare; }; + + libretro = recurseIntoAttrs (callPackage ../misc/emulators/retroarch/cores.nix { + retroarch = retroarchBare; + }); + + retrofe = callPackage ../misc/emulators/retrofe { }; + + rfc-bibtex = python3Packages.callPackage ../development/python-modules/rfc-bibtex { }; + + rpl = callPackage ../tools/text/rpl { + pythonPackages = python3Packages; + }; + + ricty = callPackage ../data/fonts/ricty { }; + + rmount = callPackage ../tools/filesystems/rmount {}; + + rss-glx = callPackage ../misc/screensavers/rss-glx { }; + + run-scaled = callPackage ../tools/X11/run-scaled { }; + + runit = callPackage ../tools/system/runit { }; + + refind = callPackage ../tools/bootloaders/refind { }; + + spectrojack = callPackage ../applications/audio/spectrojack { }; + + sift = callPackage ../tools/text/sift { }; + + xlockmore = callPackage ../misc/screensavers/xlockmore { }; + + xtrlock-pam = callPackage ../misc/screensavers/xtrlock-pam { }; + + sailsd = callPackage ../misc/sailsd { }; + + shc = callPackage ../tools/security/shc { }; + + canon-cups-ufr2 = callPackage ../misc/cups/drivers/canon { }; + + hll2390dw-cups = callPackage ../misc/cups/drivers/hll2390dw-cups { }; + + mfcj470dw-cupswrapper = callPackage ../misc/cups/drivers/mfcj470dwcupswrapper { }; + mfcj470dwlpr = pkgsi686Linux.callPackage ../misc/cups/drivers/mfcj470dwlpr { }; + + mfcj6510dw-cupswrapper = callPackage ../misc/cups/drivers/mfcj6510dwcupswrapper { }; + mfcj6510dwlpr = pkgsi686Linux.callPackage ../misc/cups/drivers/mfcj6510dwlpr { }; + + mfcl2700dncupswrapper = callPackage ../misc/cups/drivers/mfcl2700dncupswrapper { }; + mfcl2700dnlpr = pkgsi686Linux.callPackage ../misc/cups/drivers/mfcl2700dnlpr { }; + + mfcl2720dwcupswrapper = callPackage ../misc/cups/drivers/mfcl2720dwcupswrapper { }; + mfcl2720dwlpr = callPackage ../misc/cups/drivers/mfcl2720dwlpr { }; + + mfcl2740dwcupswrapper = callPackage ../misc/cups/drivers/mfcl2740dwcupswrapper { }; + mfcl2740dwlpr = callPackage ../misc/cups/drivers/mfcl2740dwlpr { }; + + mfcl8690cdwcupswrapper = callPackage ../misc/cups/drivers/mfcl8690cdwcupswrapper { }; + mfcl8690cdwlpr = callPackage ../misc/cups/drivers/mfcl8690cdwlpr { }; + + samsung-unified-linux-driver_1_00_36 = callPackage ../misc/cups/drivers/samsung/1.00.36/default.nix { }; + samsung-unified-linux-driver_1_00_37 = callPackage ../misc/cups/drivers/samsung/1.00.37.nix { }; + samsung-unified-linux-driver_4_00_39 = callPackage ../misc/cups/drivers/samsung/4.00.39 { }; + samsung-unified-linux-driver_4_01_17 = callPackage ../misc/cups/drivers/samsung/4.01.17.nix { }; + samsung-unified-linux-driver = res.samsung-unified-linux-driver_4_01_17; + + sane-backends = callPackage ../applications/graphics/sane/backends (config.sane or {}); + + sane-backends-git = callPackage ../applications/graphics/sane/backends/git.nix (config.sane or {}); + + brlaser = callPackage ../misc/cups/drivers/brlaser { }; + + fxlinuxprint = callPackage ../misc/cups/drivers/fxlinuxprint { }; + + brscan4 = callPackage ../applications/graphics/sane/backends/brscan4 { }; + + dsseries = callPackage ../applications/graphics/sane/backends/dsseries { }; + + mkSaneConfig = callPackage ../applications/graphics/sane/config.nix { }; + + sane-frontends = callPackage ../applications/graphics/sane/frontends.nix { }; + + satysfi = callPackage ../tools/typesetting/satysfi { }; + + sc-controller = pythonPackages.callPackage ../misc/drivers/sc-controller { + inherit libusb1; # Shadow python.pkgs.libusb1. + }; + + sct = callPackage ../tools/X11/sct {}; + + scylladb = callPackage ../servers/scylladb { + thrift = thrift-0_10; + }; + + seafile-shared = callPackage ../misc/seafile-shared { }; + + serviio = callPackage ../servers/serviio {}; + selinux-python = callPackage ../os-specific/linux/selinux-python { + # needs python3 bindings + libselinux = libselinux.override { python = python3; }; + libsemanage = libsemanage.override { python = python3; }; + }; + + slock = callPackage ../misc/screensavers/slock { + conf = config.slock.conf or null; + }; + + smokeping = callPackage ../tools/networking/smokeping { }; + + snapraid = callPackage ../tools/filesystems/snapraid { }; + + snscrape = with python3Packages; toPythonApplication snscrape; + + soundOfSorting = callPackage ../misc/sound-of-sorting { }; + + sourceAndTags = callPackage ../misc/source-and-tags { + hasktags = haskellPackages.hasktags; + }; + + splix = callPackage ../misc/cups/drivers/splix { }; + + steamcontroller = callPackage ../misc/drivers/steamcontroller { }; + + stern = callPackage ../applications/networking/cluster/stern { }; + + streamripper = callPackage ../applications/audio/streamripper { }; + + sqsh = callPackage ../development/tools/sqsh { }; + + jx = callPackage ../applications/networking/cluster/jx {}; + + prow = callPackage ../applications/networking/cluster/prow {}; + + inherit (callPackage ../applications/networking/cluster/terraform {}) + terraform_0_11 + terraform_0_11-full + terraform_0_12 + terraform_plugins_test + ; + + terraform = terraform_0_11; + # deprecated + terraform-full = terraform.full; + + terraform-providers = recurseIntoAttrs ( + callPackage ../applications/networking/cluster/terraform-providers {} + ); + + terraform-docs = callPackage ../applications/networking/cluster/terraform-docs {}; + + terraform-inventory = callPackage ../applications/networking/cluster/terraform-inventory {}; + + terraform-landscape = callPackage ../applications/networking/cluster/terraform-landscape {}; + + terragrunt = callPackage ../applications/networking/cluster/terragrunt {}; + + tilt = callPackage ../applications/networking/cluster/tilt {}; + + tetex = callPackage ../tools/typesetting/tex/tetex { libpng = libpng12; }; + + tewi-font = callPackage ../data/fonts/tewi {}; + + texFunctions = callPackage ../tools/typesetting/tex/nix pkgs; + + # TeX Live; see http://nixos.org/nixpkgs/manual/#sec-language-texlive + texlive = recurseIntoAttrs + (callPackage ../tools/typesetting/tex/texlive { }); + + ib-tws = callPackage ../applications/office/ib/tws { jdk=oraclejdk8; }; + + ib-controller = callPackage ../applications/office/ib/controller { jdk=oraclejdk8; }; + + vnote = libsForQt5.callPackage ../applications/office/vnote { }; + + ssh-audit = callPackage ../tools/security/ssh-audit { }; + + thermald = callPackage ../tools/system/thermald { }; + + throttled = callPackage ../tools/system/throttled { }; + + thinkfan = callPackage ../tools/system/thinkfan { }; + + tup = callPackage ../development/tools/build-managers/tup { }; + + trufflehog = callPackage ../tools/security/trufflehog { }; + + tvbrowser-bin = callPackage ../applications/misc/tvbrowser/bin.nix { }; + + tvheadend = callPackage ../servers/tvheadend { }; + + ums = callPackage ../servers/ums { }; + + unity3d = callPackage ../development/tools/unity3d { + stdenv = stdenv_32bit; + gcc_32bit = pkgsi686Linux.gcc; + inherit (gnome2) GConf; + }; + + urbit = callPackage ../misc/urbit { }; + + utf8proc = callPackage ../development/libraries/utf8proc { }; + + unicode-paracode = callPackage ../tools/misc/unicode { }; + + unixcw = callPackage ../applications/radio/unixcw { }; + + vault = callPackage ../tools/security/vault { }; + + vault-bin = callPackage ../tools/security/vault/vault-bin.nix { }; + + vaultenv = haskellPackages.vaultenv; + + vazir-fonts = callPackage ../data/fonts/vazir-fonts { }; + + vbam = callPackage ../misc/emulators/vbam { + ffmpeg = ffmpeg_2; + }; + + vice = callPackage ../misc/emulators/vice { + giflib = giflib_4_1; + }; + + viewnior = callPackage ../applications/graphics/viewnior { }; + + vimUtils = callPackage ../misc/vim-plugins/vim-utils.nix { }; + + vimPlugins = recurseIntoAttrs (callPackage ../misc/vim-plugins { + llvmPackages = llvmPackages_6; + }); + + vimprobable2-unwrapped = callPackage ../applications/networking/browsers/vimprobable2 { + webkitgtk = webkitgtk24x-gtk2; + }; + vimprobable2 = wrapFirefox vimprobable2-unwrapped { }; + + vimb-unwrapped = callPackage ../applications/networking/browsers/vimb { }; + vimb = wrapFirefox vimb-unwrapped { }; + + vips = callPackage ../tools/graphics/vips { + inherit (darwin.apple_sdk.frameworks) ApplicationServices; + }; + nip2 = callPackage ../tools/graphics/nip2 { }; + + virglrenderer = callPackage ../development/libraries/virglrenderer { }; + + vivid = callPackage ../tools/misc/vivid { }; + + vokoscreen = libsForQt5.callPackage ../applications/video/vokoscreen { }; + + vttest = callPackage ../tools/misc/vttest { }; + + wasm-pack = callPackage ../development/tools/wasm-pack { + inherit (darwin.apple_sdk.frameworks) Security; + }; + + wavegain = callPackage ../applications/audio/wavegain { }; + + wcalc = callPackage ../applications/misc/wcalc { }; + + webfs = callPackage ../servers/http/webfs { }; + + websocketd = callPackage ../applications/networking/websocketd { }; + + wikicurses = callPackage ../applications/misc/wikicurses { + pythonPackages = python3Packages; + }; + + winePackagesFor = wineBuild: lib.makeExtensible (self: with self; { + callPackage = newScope self; + + inherit wineBuild; + + inherit (callPackage ./wine-packages.nix {}) + minimal base full stable unstable staging fonts; + }); + + winePackages = recurseIntoAttrs (winePackagesFor (config.wine.build or "wine32")); + wineWowPackages = recurseIntoAttrs (winePackagesFor "wineWow"); + + wine = winePackages.full; + + wine-staging = lowPrio (winePackages.full.override { + wineRelease = "staging"; + }); + + winetricks = callPackage ../misc/emulators/wine/winetricks.nix { + inherit (gnome3) zenity; + }; + + wishbone-tool = callPackage ../development/tools/misc/wishbone-tool { }; + + with-shell = callPackage ../applications/misc/with-shell { }; + + wmutils-core = callPackage ../tools/X11/wmutils-core { }; + + wmutils-opt = callPackage ../tools/X11/wmutils-opt { }; + + wordpress = callPackage ../servers/web-apps/wordpress { }; + + wraith = callPackage ../applications/networking/irc/wraith { + openssl = openssl_1_0_2; + }; + + wxmupen64plus = callPackage ../misc/emulators/wxmupen64plus { }; + + wxsqlite3 = callPackage ../development/libraries/wxsqlite3 { + wxGTK = wxGTK30; + }; + + wxsqliteplus = callPackage ../development/libraries/wxsqliteplus { + wxGTK = wxGTK30; + }; + + x11idle = callPackage ../tools/misc/x11idle {}; + + x11docker = callPackage ../applications/virtualization/x11docker { }; + + x2x = callPackage ../tools/X11/x2x { }; + + xboxdrv = callPackage ../misc/drivers/xboxdrv { }; + + xbps = callPackage ../tools/package-management/xbps { }; + + xcftools = callPackage ../tools/graphics/xcftools { }; + + xhyve = callPackage ../applications/virtualization/xhyve { + inherit (darwin.apple_sdk.frameworks) Hypervisor vmnet; + inherit (darwin.apple_sdk.libs) xpc; + inherit (darwin) libobjc; + }; + + xinput_calibrator = callPackage ../tools/X11/xinput_calibrator { }; + + xlayoutdisplay = callPackage ../tools/X11/xlayoutdisplay { }; + + xlog = callPackage ../applications/radio/xlog { }; + + xmagnify = callPackage ../tools/X11/xmagnify { }; + + xosd = callPackage ../misc/xosd { }; + + xosview2 = callPackage ../tools/X11/xosview2 { }; + + xpad = callPackage ../applications/misc/xpad { }; + + xsane = callPackage ../applications/graphics/sane/xsane.nix { + libpng = libpng12; + sane-backends = sane-backends.override { libpng = libpng12; }; + }; + + xsw = callPackage ../applications/misc/xsw { + # Enable the next line to use this in terminal. + # Note that it requires sixel capable terminals such as mlterm + # or xterm -ti 340 + SDL = SDL_sixel; + }; + + xteddy = callPackage ../applications/misc/xteddy { }; + + xwiimote = callPackage ../misc/drivers/xwiimote { + bluez = pkgs.bluez5.override { + enableWiimote = true; + }; + }; + + xzoom = callPackage ../tools/X11/xzoom {}; + + yabause = libsForQt5.callPackage ../misc/emulators/yabause { + freeglut = null; + openal = null; + }; + + yacreader = libsForQt5.callPackage ../applications/graphics/yacreader { }; + + yadm = callPackage ../applications/version-management/yadm { }; + + yamdi = callPackage ../tools/video/yamdi { }; + + yandex-disk = callPackage ../tools/filesystems/yandex-disk { }; + + yara = callPackage ../tools/security/yara { }; + + yaxg = callPackage ../tools/graphics/yaxg {}; + + zap = callPackage ../tools/networking/zap { }; + + zopfli = callPackage ../tools/compression/zopfli { }; + + myEnvFun = callPackage ../misc/my-env { + inherit (stdenv) mkDerivation; + }; + + znc = callPackage ../applications/networking/znc { }; + + zncModules = recurseIntoAttrs ( + callPackage ../applications/networking/znc/modules.nix { } + ); + + zoneminder = callPackage ../servers/zoneminder { }; + + zsnes = pkgsi686Linux.callPackage ../misc/emulators/zsnes { }; + + xcpc = callPackage ../misc/emulators/xcpc { }; + + zxcvbn-c = callPackage ../development/libraries/zxcvbn-c { }; + + snes9x-gtk = callPackage ../misc/emulators/snes9x-gtk { }; + + openmsx = callPackage ../misc/emulators/openmsx { + python = python27; + }; + + higan = callPackage ../misc/emulators/higan { + inherit (gnome2) gtksourceview; + }; + + bullet = callPackage ../development/libraries/bullet { + inherit (darwin.apple_sdk.frameworks) Cocoa OpenGL; + }; + + bullet-roboschool = callPackage ../development/libraries/bullet/roboschool-fork.nix { + inherit (darwin.apple_sdk.frameworks) Cocoa OpenGL; + }; + + inherit (callPackages ../development/libraries/spdlog { }) + spdlog_0 spdlog_1; + + spdlog = spdlog_1; + + dart = callPackage ../development/interpreters/dart { }; + dart_stable = dart.override { version = "2.0.0"; }; + dart_old = dart.override { version = "1.24.3"; }; + dart_dev = dart.override { version = "2.0.0-dev.26.0"; }; + + httrack = callPackage ../tools/backup/httrack { }; + + httraqt = libsForQt5.callPackage ../tools/backup/httrack/qt.nix { }; + + mg = callPackage ../applications/editors/mg { }; + + mpvc = callPackage ../applications/misc/mpvc { }; + + aucdtect = callPackage ../tools/audio/aucdtect { }; + + togglesg-download = callPackage ../tools/misc/togglesg-download { }; + + discord = import ../applications/networking/instant-messengers/discord { + branch = "stable"; + inherit pkgs; + }; + + discord-ptb = import ../applications/networking/instant-messengers/discord { + branch = "ptb"; + inherit pkgs; + }; + + discord-canary = import ../applications/networking/instant-messengers/discord { + branch = "canary"; + inherit pkgs; + }; + + golden-cheetah = libsForQt5.callPackage ../applications/misc/golden-cheetah {}; + + linkchecker = callPackage ../tools/networking/linkchecker { }; + + tomb = callPackage ../os-specific/linux/tomb {}; + + tomboy = callPackage ../applications/misc/tomboy { }; + + imatix_gsl = callPackage ../development/tools/imatix_gsl {}; + + iterm2 = callPackage ../applications/misc/iterm2 {}; + + sccache = callPackage ../development/tools/misc/sccache { }; + + sequeler = callPackage ../applications/misc/sequeler { }; + + sequelpro = callPackage ../applications/misc/sequelpro {}; + + sidequest = callPackage ../applications/misc/sidequest {}; + + maphosts = callPackage ../tools/networking/maphosts {}; + + zimg = callPackage ../development/libraries/zimg { }; + + wtf = callPackage ../applications/misc/wtf { }; + + zk-shell = callPackage ../applications/misc/zk-shell { }; + + tora = libsForQt5.callPackage ../development/tools/tora {}; + + xulrunner = firefox-unwrapped; + + xrq = callPackage ../applications/misc/xrq { }; + + nitrokey-app = libsForQt5.callPackage ../tools/security/nitrokey-app { }; + nitrokey-udev-rules = callPackage ../tools/security/nitrokey-app/udev-rules.nix { }; + + fpm2 = callPackage ../tools/security/fpm2 { }; + + simplenote = callPackage ../applications/misc/simplenote { }; + + hy = callPackage ../development/interpreters/hy {}; + + check-uptime = callPackage ../servers/monitoring/plugins/uptime.nix { }; + + ghc-standalone-archive = callPackage ../os-specific/darwin/ghc-standalone-archive { inherit (darwin) cctools; }; + + vdr = callPackage ../applications/video/vdr { }; + vdrPlugins = recurseIntoAttrs (callPackages ../applications/video/vdr/plugins.nix { }); + wrapVdr = callPackage ../applications/video/vdr/wrapper.nix {}; + + chrome-export = callPackage ../tools/misc/chrome-export {}; + + chrome-gnome-shell = callPackage ../desktops/gnome-3/extensions/chrome-gnome-shell {}; + + chrome-token-signing = libsForQt5.callPackage ../tools/security/chrome-token-signing {}; + + NSPlist = callPackage ../development/libraries/NSPlist {}; + + PlistCpp = callPackage ../development/libraries/PlistCpp {}; + + xib2nib = callPackage ../development/tools/xib2nib {}; + + linode-cli = callPackage ../tools/virtualization/linode-cli { }; + + hss = callPackage ../tools/networking/hss {}; + + undaemonize = callPackage ../tools/system/undaemonize {}; + + houdini = callPackage ../applications/misc/houdini {}; + + xtermcontrol = callPackage ../applications/misc/xtermcontrol {}; + + openfst = callPackage ../development/libraries/openfst {}; + + duti = callPackage ../os-specific/darwin/duti {}; + + dnstracer = callPackage ../tools/networking/dnstracer { + inherit (darwin) libresolv; + }; + + dsniff = callPackage ../tools/networking/dsniff {}; + + wal-g = callPackage ../tools/backup/wal-g {}; + + tlwg = callPackage ../data/fonts/tlwg { }; + + simplehttp2server = callPackage ../servers/simplehttp2server { }; + + diceware = callPackage ../tools/security/diceware { }; + + xml2rfc = callPackage ../tools/typesetting/xml2rfc { }; + + mmark = callPackage ../tools/typesetting/mmark { }; + + wire-desktop = callPackage ../applications/networking/instant-messengers/wire-desktop { }; + + teseq = callPackage ../applications/misc/teseq { }; + + ape = callPackage ../applications/misc/ape { }; + attemptoClex = callPackage ../applications/misc/ape/clex.nix { }; + apeClex = callPackage ../applications/misc/ape/apeclex.nix { }; + + # Unix tools + unixtools = recurseIntoAttrs (callPackages ./unix-tools.nix { }); + inherit (unixtools) hexdump ps logger eject umount + mount wall hostname more sysctl getconf + getent locale killall xxd watch; + + fts = if stdenv.hostPlatform.isMusl then netbsd.fts else null; + + netbsd = callPackages ../os-specific/bsd/netbsd {}; + netbsdCross = callPackages ../os-specific/bsd/netbsd { + stdenv = crossLibcStdenv; + }; + + yrd = callPackage ../tools/networking/yrd { }; + + powershell = callPackage ../shells/powershell { }; + + doing = callPackage ../applications/misc/doing { }; + + undervolt = callPackage ../os-specific/linux/undervolt { }; + + alibuild = callPackage ../development/tools/build-managers/alibuild { + python = python27; + }; + + tsung = callPackage ../applications/networking/tsung {}; + + bcompare = libsForQt5.callPackage ../applications/version-management/bcompare {}; + + qmk_firmware = callPackage ../development/misc/qmk_firmware { + avrgcc = pkgsCross.avr.buildPackages.gcc; + avrbinutils = pkgsCross.avr.buildPackages.binutils; + gcc-arm-embedded = pkgsCross.arm-embedded.buildPackages.gcc; + gcc-armhf-embedded = pkgsCross.armhf-embedded.buildPackages.gcc; + }; + + tdm = callPackage ../games/tdm { }; + + newlib = callPackage ../development/misc/newlib { }; + newlibCross = callPackage ../development/misc/newlib { + stdenv = crossLibcStdenv; + }; + + omnisharp-roslyn = callPackage ../development/tools/omnisharp-roslyn { }; + + wasmtime = callPackage ../development/interpreters/wasmtime {}; + + bemenu = callPackage ../applications/misc/bemenu { }; + + dapper = callPackage ../development/tools/dapper { }; + + kube3d = callPackage ../applications/networking/cluster/kube3d {}; + + zfs-replicate = python3Packages.callPackage ../tools/backup/zfs-replicate { }; + + runwayml = callPackage ../applications/graphics/runwayml {}; + + uhubctl = callPackage ../tools/misc/uhubctl {}; + + kodelife = callPackage ../applications/graphics/kodelife {}; +} diff --git a/third_party/crates/rnix-0.14.0/benches/all-packages.rs b/third_party/crates/rnix-0.14.0/benches/all-packages.rs new file mode 100644 index 0000000..789afd5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/benches/all-packages.rs @@ -0,0 +1,15 @@ +use criterion::{criterion_group, criterion_main, Criterion, Throughput}; + +fn all_packages(c: &mut Criterion) { + let input = include_str!("all-packages.nix"); + let mut group = c.benchmark_group("all-packages"); + group.throughput(Throughput::Bytes(input.len() as u64)); + group.sample_size(30); + group.bench_with_input("all-packages", input, move |b, input| { + b.iter(|| rnix::Root::parse(input)) + }); + group.finish(); +} + +criterion_group!(benches, all_packages); +criterion_main!(benches); diff --git a/third_party/crates/rnix-0.14.0/default.nix b/third_party/crates/rnix-0.14.0/default.nix new file mode 100644 index 0000000..af9eab6 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/default.nix @@ -0,0 +1,9 @@ +let + flake-compat = builtins.fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/12c64ca55c1014cdc1b16ed5a804aa8576601ff2.tar.gz"; + sha256 = "0jm6nzb83wa6ai17ly9fzpqc40wg1viib8klq8lby54agpl213w5"; + }; +in +(import flake-compat { + src = ./.; +}).defaultNix.default diff --git a/third_party/crates/rnix-0.14.0/examples/dump-ast.rs b/third_party/crates/rnix-0.14.0/examples/dump-ast.rs new file mode 100644 index 0000000..8ba055c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/examples/dump-ast.rs @@ -0,0 +1,24 @@ +use std::{env, fs}; + +fn main() { + let mut iter = env::args().skip(1).peekable(); + if iter.peek().is_none() { + eprintln!("Usage: dump-ast "); + return; + } + for file in iter { + let content = match fs::read_to_string(file) { + Ok(content) => content, + Err(err) => { + eprintln!("error reading file: {}", err); + return; + } + }; + let parse = rnix::Root::parse(&content); + + for error in parse.errors() { + println!("error: {}", error); + } + println!("{:#?}", parse.tree()); + } +} diff --git a/third_party/crates/rnix-0.14.0/examples/error-report.rs b/third_party/crates/rnix-0.14.0/examples/error-report.rs new file mode 100644 index 0000000..e14bc9d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/examples/error-report.rs @@ -0,0 +1,67 @@ +use rnix::ParseError; +use std::{env, fs}; + +fn main() { + let file = match env::args().nth(1) { + Some(file) => file, + None => { + eprintln!("Usage: error-report "); + return; + } + }; + let content = match fs::read_to_string(&file) { + Ok(content) => content, + Err(err) => { + eprintln!("error reading file: {}", err); + return; + } + }; + let ast = rnix::Root::parse(&content); + for error in ast.errors() { + let range = match error { + ParseError::Unexpected(range) => range, + ParseError::UnexpectedExtra(range) => range, + ParseError::UnexpectedWanted(_, range, _) => range, + ParseError::UnexpectedDoubleBind(range) => range, + ParseError::DuplicatedArgs(range, _) => range, + err => { + eprintln!("error: {}", err); + continue; + } + }; + eprintln!("----- ERROR -----"); + eprintln!("{}", error); + let start = usize::from(range.start()); + let start_row = content[..start].lines().count() - 1; + let start_line = content[..start].rfind('\n').map(|i| i + 1).unwrap_or(0); + let start_col = content[start_line..start].chars().count(); + let end = usize::from(range.end()); + let end_row = content[..end].lines().count() - 1; + let end_line = content[..end].rfind('\n').map(|i| i + 1).unwrap_or(0); + let end_col = content[end_line..end].chars().count(); + + let mut line_len = 1; + let mut line = end_row; + while line >= 10 { + line /= 10; + line_len += 1; + } + + let i = start_row.saturating_sub(1); + for (i, line) in content.lines().enumerate().skip(i).take(end_row - i + 1) { + println!("{:line_len$} {}", i + 1, line, line_len = line_len); + if i >= start_row && i <= end_row { + print!("{:line_len$} ", "", line_len = line_len); + let mut end_col = if i == end_row { end_col } else { line.chars().count() }; + if i == start_row { + print!("{:indent$}", "", indent = start_col); + end_col -= start_col; + } + for _ in 0..end_col { + print!("^"); + } + println!(); + } + } + } +} diff --git a/third_party/crates/rnix-0.14.0/examples/from-stdin.rs b/third_party/crates/rnix-0.14.0/examples/from-stdin.rs new file mode 100644 index 0000000..3b2a713 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/examples/from-stdin.rs @@ -0,0 +1,13 @@ +use std::{io, io::Read}; + +fn main() { + let mut content = String::new(); + io::stdin().read_to_string(&mut content).expect("could not read nix from stdin"); + let ast = rnix::Root::parse(&content); + + for error in ast.errors() { + println!("error: {}", error); + } + + println!("{:#?}", ast.tree()); +} diff --git a/third_party/crates/rnix-0.14.0/examples/list-fns.rs b/third_party/crates/rnix-0.14.0/examples/list-fns.rs new file mode 100644 index 0000000..0fc178f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/examples/list-fns.rs @@ -0,0 +1,95 @@ +use std::{env, error::Error, fs}; + +use rnix::{ + ast::{self, AstToken, HasEntry}, + match_ast, NodeOrToken, SyntaxNode, +}; +use rowan::ast::AstNode; + +macro_rules! single_match { + ($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? => $captured:expr) => { + match $expression { + $( $pattern )|+ $( if $guard )? => Some($captured), + _ => None + } + }; +} + +fn main() -> Result<(), Box> { + let file = match env::args().nth(1) { + Some(file) => file, + None => { + eprintln!("Usage: list-fns "); + return Ok(()); + } + }; + let content = fs::read_to_string(&file)?; + let ast = rnix::Root::parse(&content).ok()?; + let expr = ast.expr().unwrap(); + let set = match expr { + ast::Expr::AttrSet(set) => set, + _ => return Err("root isn't a set".into()), + }; + for entry in set.entries() { + if let ast::Entry::AttrpathValue(attrpath_value) = entry { + if let Some(ast::Expr::Lambda(lambda)) = attrpath_value.value() { + let attrpath = attrpath_value.attrpath().unwrap(); + let ident = attrpath.attrs().last().and_then(|attr| match attr { + ast::Attr::Ident(ident) => Some(ident), + _ => None, + }); + let s = ident.as_ref().map_or_else( + || "error".to_string(), + |ident| ident.ident_token().unwrap().text().to_string(), + ); + println!("Function name: {}", s); + { + let comments = comments_before(attrpath_value.syntax()); + if !comments.is_empty() { + println!("--> Doc: {comments}"); + } + } + + let mut value = Some(lambda); + while let Some(lambda) = value { + let s = lambda + .param() + .as_ref() + .map_or_else(|| "error".to_string(), |param| param.to_string()); + println!("-> Param: {}", s); + { + let comments = comments_before(lambda.syntax()); + if !comments.is_empty() { + println!("--> Doc: {comments}"); + } + } + value = + single_match!(lambda.body().unwrap(), ast::Expr::Lambda(lambda) => lambda); + } + println!(); + } + } + } + + Ok(()) +} + +fn comments_before(node: &SyntaxNode) -> String { + node.siblings_with_tokens(rowan::Direction::Prev) + // rowan always returns the first node for some reason + .skip(1) + .map_while(|element| match element { + NodeOrToken::Token(token) => match_ast! { + match token { + ast::Comment(it) => Some(Some(it)), + ast::Whitespace(_) => Some(None), + _ => None, + } + }, + _ => None, + }) + .flatten() + .map(|s| s.text().trim().to_string()) + .collect::>() + .join("\n ") +} diff --git a/third_party/crates/rnix-0.14.0/examples/preserve.rs b/third_party/crates/rnix-0.14.0/examples/preserve.rs new file mode 100644 index 0000000..a6c8c4f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/examples/preserve.rs @@ -0,0 +1,19 @@ +use std::{env, fs}; + +fn main() { + let mut iter = env::args().skip(1).peekable(); + if iter.peek().is_none() { + eprintln!("Usage: preserve "); + return; + } + for file in iter { + let content = match fs::read_to_string(file) { + Ok(content) => content, + Err(err) => { + eprintln!("error reading file: {}", err); + return; + } + }; + print!("{}", rnix::Root::parse(&content).tree()); + } +} diff --git a/third_party/crates/rnix-0.14.0/examples/test-nixpkgs.rs b/third_party/crates/rnix-0.14.0/examples/test-nixpkgs.rs new file mode 100644 index 0000000..716cc0d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/examples/test-nixpkgs.rs @@ -0,0 +1,48 @@ +use std::{env, error::Error, fs, path::Path}; + +fn main() -> Result<(), Box> { + let path = env::var("NIX_PATH")?; + let nixpkgs = + path.split(':').find(|s| s.starts_with("nixpkgs=")).ok_or("no store path found")?; + + println!("Nix store path: {}", nixpkgs); + + recurse(Path::new(&nixpkgs["nixpkgs=".len()..])) +} +fn recurse(path: &Path) -> Result<(), Box> { + if path.metadata()?.is_file() { + if path.extension().and_then(|s| s.to_str()) != Some("nix") { + return Ok(()); + } + + println!("Checking {}", path.display()); + let original = fs::read_to_string(path)?; + if original.trim().is_empty() { + return Ok(()); + } + + let parsed = rnix::Root::parse(&original).tree().to_string(); + if original != parsed { + eprintln!("Original input does not match parsed output!"); + println!("Input:"); + println!("----------"); + println!("{}", original); + println!("----------"); + println!("Output:"); + println!("----------"); + println!("{}", parsed); + println!("----------"); + return Err("parsing error".into()); + } + return Ok(()); + } else { + for entry in path.read_dir()? { + let entry = entry?; + if entry.file_type()?.is_symlink() { + continue; + } + recurse(&entry.path())?; + } + } + Ok(()) +} diff --git a/third_party/crates/rnix-0.14.0/flake.lock b/third_party/crates/rnix-0.14.0/flake.lock new file mode 100644 index 0000000..f8b1373 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/flake.lock @@ -0,0 +1,116 @@ +{ + "nodes": { + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1769670296, + "narHash": "sha256-0OzQzsufPwHUTJMAgVf+TXPFG+8x5xrYwz1/M/kI+7o=", + "owner": "nix-community", + "repo": "fenix", + "rev": "b00052920f71c43987b44c804196c083eb0fa1bf", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "import-cargo": { + "locked": { + "lastModified": 1594305518, + "narHash": "sha256-frtArgN42rSaEcEOYWg8sVPMUK+Zgch3c+wejcpX3DY=", + "owner": "edolstra", + "repo": "import-cargo", + "rev": "25d40be4a73d40a2572e0cc233b83253554f06c5", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "import-cargo", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1769461804, + "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "fenix": "fenix", + "import-cargo": "import-cargo", + "nixpkgs": "nixpkgs", + "utils": "utils" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1769526882, + "narHash": "sha256-64CZX2vKsfSLKnTCZ0pbc1jPvixWWwuT382g3QHBz5c=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "40cda2f4bd585c1cb99ae4eb025968b8dc2eec42", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/third_party/crates/rnix-0.14.0/flake.nix b/third_party/crates/rnix-0.14.0/flake.nix new file mode 100644 index 0000000..75cae82 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/flake.nix @@ -0,0 +1,85 @@ +{ + description = "Rust-based parser for nix files"; + + inputs = { + utils.url = "github:numtide/flake-utils"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + import-cargo.url = "github:edolstra/import-cargo"; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, utils, import-cargo, fenix }: + { + overlay = final: prev: let + target = final.stdenv.hostPlatform.rust.rustcTarget; + flags = "--release --offline --target ${target}"; + inherit (import-cargo.builders) importCargo; + in { + rnix-parser = final.stdenv.mkDerivation { + pname = "rnix-parser"; + version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version; + src = final.lib.cleanSource ./.; + nativeBuildInputs = with final; [ + rustc cargo + (importCargo { lockFile = ./Cargo.lock; inherit (final) pkgs; }).cargoHome + ]; + + outputs = [ "out" "doc" ]; + doCheck = true; + + buildPhase = '' + cargo build ${flags} + cargo doc ${flags} + ''; + + checkPhase = '' + cargo test ${flags} + cargo bench + ''; + + installPhase = '' + mkdir -p $out/lib + mkdir -p $doc/share/doc/rnix + + cp -r ./target/${target}/doc $doc/share/doc/rnix + cp ./target/${target}/release/librnix.rlib $out/lib/ + ''; + }; + }; + } + // utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; overlays = [ self.overlay ]; }; + fenixPkgs = fenix.packages.${system}; + nightlyToolchain = fenixPkgs.combine [ + fenixPkgs.minimal.cargo + fenixPkgs.minimal.rustc + ]; + in + rec { + # `nix develop` + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ rustfmt rustc cargo clippy ]; + }; + + # `nix develop .#fuzz` - for running cargo-fuzz + devShells.fuzz = pkgs.mkShell { + buildInputs = [ + nightlyToolchain + pkgs.cargo-fuzz + ]; + # libFuzzer needs libstdc++ + LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib"; + }; + + # Backwards compat + devShell = devShells.default; + + packages.rnix-parser = pkgs.rnix-parser; + defaultPackage = packages.rnix-parser; + } + ); +} diff --git a/third_party/crates/rnix-0.14.0/rustfmt.toml b/third_party/crates/rnix-0.14.0/rustfmt.toml new file mode 100644 index 0000000..2a35f02 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/rustfmt.toml @@ -0,0 +1 @@ +use_small_heuristics = "Max" diff --git a/third_party/crates/rnix-0.14.0/shell.nix b/third_party/crates/rnix-0.14.0/shell.nix new file mode 100644 index 0000000..40cfa40 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/shell.nix @@ -0,0 +1,9 @@ +let + flake-compat = builtins.fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; + sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; + }; +in +(import flake-compat { + src = ./.; +}).shellNix.default diff --git a/third_party/crates/rnix-0.14.0/src/ast.rs b/third_party/crates/rnix-0.14.0/src/ast.rs new file mode 100644 index 0000000..93454ee --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/ast.rs @@ -0,0 +1,73 @@ +//! Provides a type system for the AST, in some sense + +mod expr_ext; +mod interpol; +mod nodes; +mod operators; +mod path_util; + +pub use path_util::Path; +mod str_util; +mod tokens; + +use crate::{NixLanguage, SyntaxKind, SyntaxToken}; + +pub use expr_ext::LiteralKind; +pub use interpol::*; +pub use nodes::*; +pub use operators::{BinOpKind, UnaryOpKind}; +pub use tokens::*; + +pub trait AstNode: rowan::ast::AstNode {} + +impl AstNode for T where T: rowan::ast::AstNode {} + +pub trait AstToken { + fn can_cast(from: SyntaxKind) -> bool + where + Self: Sized; + + /// Cast an untyped token into this strongly-typed token. This will return + /// None if the type was not correct. + fn cast(from: SyntaxToken) -> Option + where + Self: Sized; + + fn syntax(&self) -> &SyntaxToken; +} + +mod support { + use rowan::ast::AstChildren; + + use super::{AstNode, AstToken}; + use crate::{SyntaxElement, SyntaxKind, SyntaxToken}; + + pub(super) fn nth(parent: &N, n: usize) -> Option { + parent.syntax().children().flat_map(NN::cast).nth(n) + } + + pub(super) fn children(parent: &N) -> AstChildren { + rowan::ast::support::children(parent.syntax()) + } + + pub(super) fn token(parent: &N) -> Option { + children_tokens(parent).next() + } + + /// Token untyped + pub(super) fn token_u(parent: &N, kind: SyntaxKind) -> Option { + children_tokens_u(parent).find(|it| it.kind() == kind) + } + + pub(super) fn children_tokens(parent: &N) -> impl Iterator { + parent + .syntax() + .children_with_tokens() + .filter_map(SyntaxElement::into_token) + .filter_map(T::cast) + } + + pub(super) fn children_tokens_u(parent: &N) -> impl Iterator { + parent.syntax().children_with_tokens().filter_map(SyntaxElement::into_token) + } +} diff --git a/third_party/crates/rnix-0.14.0/src/ast/expr_ext.rs b/third_party/crates/rnix-0.14.0/src/ast/expr_ext.rs new file mode 100644 index 0000000..345d163 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/ast/expr_ext.rs @@ -0,0 +1,29 @@ +use crate::ast::{self, support::*}; + +// this is a separate type because it mixes tokens and nodes +// for example, a Str is a node because it can contain nested subexpressions but an Integer is a token. +// This means that we have to write it out manually instead of using the macro to create the type for us. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum LiteralKind { + Float(ast::Float), + Integer(ast::Integer), + Uri(ast::Uri), +} + +impl ast::Literal { + pub fn kind(&self) -> LiteralKind { + if let Some(it) = token(self) { + return LiteralKind::Float(it); + } + + if let Some(it) = token(self) { + return LiteralKind::Integer(it); + } + + if let Some(it) = token(self) { + return LiteralKind::Uri(it); + } + + unreachable!() + } +} diff --git a/third_party/crates/rnix-0.14.0/src/ast/interpol.rs b/third_party/crates/rnix-0.14.0/src/ast/interpol.rs new file mode 100644 index 0000000..c00474c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/ast/interpol.rs @@ -0,0 +1,5 @@ +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum InterpolPart { + Literal(T), + Interpolation(super::Interpol), +} diff --git a/third_party/crates/rnix-0.14.0/src/ast/nodes.rs b/third_party/crates/rnix-0.14.0/src/ast/nodes.rs new file mode 100644 index 0000000..1748a0d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/ast/nodes.rs @@ -0,0 +1,464 @@ +use crate::{NixLanguage, SyntaxKind, SyntaxKind::*, SyntaxNode, SyntaxToken}; + +use super::{operators::BinOpKind, support::*, AstNode, UnaryOpKind}; +use rowan::ast::{AstChildren, AstNode as OtherAstNode}; + +pub trait HasEntry: AstNode { + fn entries(&self) -> AstChildren + where + Self: Sized, + { + children(self) + } + + fn attrpath_values(&self) -> AstChildren + where + Self: Sized, + { + children(self) + } + + fn inherits(&self) -> AstChildren + where + Self: Sized, + { + children(self) + } +} + +macro_rules! node { + ( + #[from($kind:ident)] + $(#[$meta:meta])* + struct $name:ident; + ) => { + #[derive(Debug, Clone, PartialEq, Eq, Hash)] + $(#[$meta])* + pub struct $name(pub(super) SyntaxNode); + + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } + } + + impl rowan::ast::AstNode for $name { + type Language = crate::NixLanguage; + + fn can_cast(kind: crate::SyntaxKind) -> bool { + kind == $kind + } + + fn cast(from: SyntaxNode) -> Option { + if Self::can_cast(from.kind()) { + Some(Self(from)) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.0 + } + } + + impl $name { + pub const KIND: SyntaxKind = $kind; + } + }; + ( + #[from($($variant:ident),* $(,)?)] + $(#[$meta:meta])* + enum $name:ident; + ) => { + #[derive(Debug, Clone, PartialEq, Eq, Hash)] + $(#[$meta])* + pub enum $name { + $( + $variant($variant), + )* + } + + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } + } + + impl rowan::ast::AstNode for $name { + type Language = NixLanguage; + + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, $($variant::KIND)|*) + } + + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + $( + $variant::KIND => $name::$variant($variant(syntax)) + ),*, + _ => return None, + }; + Some(res) + } + + fn syntax(&self) -> &SyntaxNode { + match self { + $( + $name::$variant(it) => &it.0, + )* + } + } + } + + $( + impl From<$variant> for $name { + fn from(node: $variant) -> $name { $name::$variant(node) } + } + + impl TryFrom<$name> for $variant { + type Error = (); + + fn try_from(node: $name) -> Result<$variant, ()> { + match node { + $name::$variant(it) => Ok(it), + _ => Err(()), + } + } + } + )* + }; +} + +macro_rules! tg { + ( + $(#[doc=$doc:tt])? + $name:ident, + $token:tt + ) => { + $(#[doc=$doc])? + pub fn $name(&self) -> Option { + token_u(self, T![$token]) + } + }; +} + +macro_rules! ng { + ( + $(#[$meta:meta])* + $name:ident, + $ty:ty, + $i:expr + ) => { + $(#[$meta])* + pub fn $name(&self) -> Option<$ty> { + nth(self, $i) + } + }; + ( + $(#[$meta:meta])* + $name:ident, + [$ty:ty] + ) => { + $(#[$meta])* + pub fn $name(&self) -> AstChildren<$ty> { + children(self) + } + }; +} + +node! { #[from(NODE_LITERAL)] struct Literal; } + +node! { + #[from( + Apply, + Assert, + Error, + IfElse, + Select, + Str, + PathAbs, + PathRel, + PathHome, + PathSearch, + Literal, + Lambda, + LegacyLet, + LetIn, + List, + BinOp, + Paren, + Root, + AttrSet, + UnaryOp, + Ident, + With, + HasAttr, + CurPos, + )] + /// An expression. The fundamental nix ast type. + enum Expr; +} + +node! { + #[from( + Ident, + Dynamic, + Str, + )] + enum Attr; +} + +node! { #[from(NODE_IDENT)] struct Ident; } + +impl Ident { + // A NODE_IDENT may either have a nested TOKEN_OR if the identifier was "or" or TOKEN_IDENT for everything else + tg! { ident_token, TOKEN_IDENT } +} + +node! { #[from(NODE_APPLY)] struct Apply; } + +impl Apply { + ng! { lambda, Expr, 0 } + ng! { argument, Expr, 1 } +} + +node! { #[from(NODE_ASSERT)] struct Assert; } + +impl Assert { + tg! { assert_token, assert } + ng! { condition, Expr, 0 } + ng! { body, Expr, 1 } +} + +node! { #[from(NODE_ATTRPATH)] struct Attrpath; } + +impl Attrpath { + ng! { attrs, [Attr] } +} + +node! { #[from(NODE_DYNAMIC)] struct Dynamic; } + +impl Dynamic { + tg! { interpol_start_token, TOKEN_INTERPOL_START } + ng! { expr, Expr, 0 } + tg! { interpol_end_token, TOKEN_INTERPOL_END } +} + +node! { #[from(NODE_ERROR)] struct Error; } + +node! { #[from(NODE_IF_ELSE)] struct IfElse; } + +impl IfElse { + tg! { if_token, if } + ng! { condition, Expr, 0 } + tg! { then_token, then } + ng! { body, Expr, 1 } + tg! { else_token, else } + ng! { else_body, Expr, 2 } +} + +node! { #[from(NODE_SELECT)] struct Select; } + +impl Select { + ng! { expr, Expr, 0 } + tg! { dot_token, . } + ng! { attrpath, Attrpath, 0 } + tg! { or_token, or } + ng! { default_expr, Expr, 1 } +} + +node! { #[from(NODE_INHERIT)] struct Inherit; } + +impl Inherit { + tg! { inherit_token, inherit } + ng! { from, InheritFrom, 0 } + ng! { attrs, [Attr] } +} + +node! { #[from(NODE_INHERIT_FROM)] struct InheritFrom; } + +impl InheritFrom { + tg! { l_paren_token, '(' } + ng! { expr, Expr, 0 } + tg! { r_paren_token, ')' } +} + +node! { #[from(NODE_PATH_ABS)] struct PathAbs; } +node! { #[from(NODE_PATH_REL)] struct PathRel; } +node! { #[from(NODE_PATH_HOME)] struct PathHome; } +node! { #[from(NODE_PATH_SEARCH)] struct PathSearch; } + +node! { + #[from( + PathAbs, + PathRel, + PathHome, + PathSearch, + )] + enum Path; +} + +node! { #[from(NODE_STRING)] struct Str; } + +node! { #[from(NODE_INTERPOL)] struct Interpol; } + +impl Interpol { + ng! { expr, Expr, 0 } +} + +node! { #[from(NODE_LAMBDA)] struct Lambda; } + +impl Lambda { + ng! { param, Param, 0 } + tg! { token_colon, : } + ng! { body, Expr, 0 } +} + +node! { #[from(NODE_LEGACY_LET)] struct LegacyLet; } + +impl HasEntry for LegacyLet {} + +impl LegacyLet { + tg! { let_token, let } + tg! { curly_open_token, '{' } + tg! { curly_close_token, '}' } +} + +node! { #[from(NODE_LET_IN)] struct LetIn; } + +impl HasEntry for LetIn {} + +impl LetIn { + tg! { let_token, let } + tg! { in_token, in } + ng! { body, Expr, 0 } +} + +node! { #[from(NODE_LIST)] struct List; } + +impl List { + tg! { l_brack_token, '[' } + ng! { items, [Expr] } + tg! { r_brack_token, ']' } +} + +node! { #[from(NODE_BIN_OP)] struct BinOp; } + +impl BinOp { + ng! { lhs, Expr, 0 } + + pub fn operator(&self) -> Option { + children_tokens_u(self).find_map(|t| BinOpKind::from_kind(t.kind())) + } + + ng! { rhs, Expr, 1 } +} + +node! { #[from(NODE_PAREN)] struct Paren; } + +impl Paren { + tg! { l_paren_token, '(' } + ng! { expr, Expr, 0 } + tg! { r_paren_token, ')' } +} + +node! { #[from(NODE_PAT_BIND)] struct PatBind; } + +impl PatBind { + ng! { ident, Ident, 0 } +} + +node! { #[from(NODE_PAT_ENTRY)] struct PatEntry; } + +impl PatEntry { + ng! { ident, Ident, 0 } + tg! { question_token, ? } + ng! { default, Expr, 1 } +} + +node! { #[from(NODE_IDENT_PARAM)] struct IdentParam; } + +impl IdentParam { + ng! { ident, Ident, 0 } +} + +node! { + #[from( + Pattern, + IdentParam, + )] + enum Param; +} + +node! { #[from(NODE_PATTERN)] struct Pattern; } + +impl Pattern { + tg! { at_token, @ } + ng! { pat_entries, [PatEntry] } + tg! { ellipsis_token, ... } + ng! { pat_bind, PatBind, 0 } +} + +node! { #[from(NODE_ROOT)] struct Root; } + +impl Root { + ng! { expr, Expr, 0 } +} + +node! { #[from(NODE_ATTR_SET)] struct AttrSet; } + +impl HasEntry for AttrSet {} + +impl AttrSet { + tg! { rec_token, rec } + tg! { l_curly_token, '{' } + tg! { r_curly_token, '}' } +} + +node! { + #[from( + Inherit, + AttrpathValue, + )] + enum Entry; +} + +node! { #[from(NODE_ATTRPATH_VALUE)] struct AttrpathValue; } + +impl AttrpathValue { + ng! { attrpath, Attrpath, 0 } + tg! { assign_token, = } + ng! { value, Expr, 0 } +} + +node! { #[from(NODE_UNARY_OP)] struct UnaryOp; } + +impl UnaryOp { + pub fn operator(&self) -> Option { + children_tokens_u(self).find_map(|t| UnaryOpKind::from_kind(t.kind())) + } + ng! { expr, Expr, 0 } +} + +node! { #[from(NODE_WITH)] struct With; } + +impl With { + tg! { with_token, with } + ng! { namespace, Expr, 0 } + tg! { semicolon_token, ; } + ng! { body, Expr, 1 } +} + +node! { #[from(NODE_HAS_ATTR)] struct HasAttr; } + +impl HasAttr { + ng! { expr, Expr, 0 } + tg! { question_token, ? } + ng! { attrpath, Attrpath, 0 } +} + +node! { #[from(NODE_CUR_POS)] struct CurPos; } + +impl CurPos { + tg! { cur_pos_token, __curPos } +} diff --git a/third_party/crates/rnix-0.14.0/src/ast/operators.rs b/third_party/crates/rnix-0.14.0/src/ast/operators.rs new file mode 100644 index 0000000..b908aa6 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/ast/operators.rs @@ -0,0 +1,71 @@ +use crate::SyntaxKind::{self, *}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum BinOpKind { + Concat, + Update, + + Add, + Sub, + Mul, + Div, + + And, + Equal, + Implication, + Less, + LessOrEq, + More, + MoreOrEq, + NotEqual, + Or, + PipeRight, + PipeLeft, +} + +impl BinOpKind { + /// Get the operation kind from a SyntaxKind in the AST + pub fn from_kind(token: SyntaxKind) -> Option { + match token { + TOKEN_CONCAT => Some(BinOpKind::Concat), + TOKEN_UPDATE => Some(BinOpKind::Update), + + TOKEN_ADD => Some(BinOpKind::Add), + TOKEN_SUB => Some(BinOpKind::Sub), + TOKEN_MUL => Some(BinOpKind::Mul), + TOKEN_DIV => Some(BinOpKind::Div), + + TOKEN_AND_AND => Some(BinOpKind::And), + TOKEN_EQUAL => Some(BinOpKind::Equal), + TOKEN_IMPLICATION => Some(BinOpKind::Implication), + TOKEN_LESS => Some(BinOpKind::Less), + TOKEN_LESS_OR_EQ => Some(BinOpKind::LessOrEq), + TOKEN_MORE => Some(BinOpKind::More), + TOKEN_MORE_OR_EQ => Some(BinOpKind::MoreOrEq), + TOKEN_NOT_EQUAL => Some(BinOpKind::NotEqual), + TOKEN_OR_OR => Some(BinOpKind::Or), + + TOKEN_PIPE_RIGHT => Some(BinOpKind::PipeRight), + TOKEN_PIPE_LEFT => Some(BinOpKind::PipeLeft), + + _ => None, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum UnaryOpKind { + Invert, + Negate, +} + +impl UnaryOpKind { + /// Get the operation kind from a token in the AST + pub fn from_kind(kind: SyntaxKind) -> Option { + match kind { + TOKEN_INVERT => Some(UnaryOpKind::Invert), + TOKEN_SUB => Some(UnaryOpKind::Negate), + _ => None, + } + } +} diff --git a/third_party/crates/rnix-0.14.0/src/ast/path_util.rs b/third_party/crates/rnix-0.14.0/src/ast/path_util.rs new file mode 100644 index 0000000..d521729 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/ast/path_util.rs @@ -0,0 +1,204 @@ +use crate::kinds::SyntaxKind::{TOKEN_PATH_ABS, TOKEN_PATH_HOME, TOKEN_PATH_REL}; + +use rowan::{ast::AstNode as OtherAstNode, NodeOrToken}; + +pub use super::nodes::Path; +use super::{ + nodes::{PathAbs, PathHome, PathRel, PathSearch}, + AstToken, InterpolPart, PathContent, +}; +use crate::ast; + +fn extract_path_parts(node: &T) -> Vec> { + node.syntax() + .children_with_tokens() + .map(|child| match child { + NodeOrToken::Token(token) => { + debug_assert!(matches!( + token.kind(), + TOKEN_PATH_ABS | TOKEN_PATH_REL | TOKEN_PATH_HOME + )); + InterpolPart::Literal(PathContent::cast(token).unwrap()) + } + NodeOrToken::Node(node) => { + InterpolPart::Interpolation(ast::Interpol::cast(node).unwrap()) + } + }) + .collect() +} + +// Direct methods for interpolatable path types +impl PathAbs { + pub fn parts(&self) -> Vec> { + extract_path_parts(self) + } +} + +impl PathRel { + pub fn parts(&self) -> Vec> { + extract_path_parts(self) + } +} + +impl PathHome { + pub fn parts(&self) -> Vec> { + extract_path_parts(self) + } +} + +// Direct methods for search path +impl PathSearch { + /// Get the content of a search path + pub fn content(&self) -> Option { + self.syntax() + .children_with_tokens() + .filter_map(|child| child.into_token().and_then(PathContent::cast)) + .next() + } +} + +/// Extension methods for the Path enum +impl Path { + /// Get parts from any path type in a unified way + pub fn parts(&self) -> Vec> { + match self { + // For interpolatable paths, get their parts + Path::PathAbs(p) => p.parts(), + Path::PathRel(p) => p.parts(), + Path::PathHome(p) => p.parts(), + // For search paths, return a single literal component if content exists + Path::PathSearch(p) => { + if let Some(content) = p.content() { + vec![InterpolPart::Literal(content)] + } else { + vec![] + } + } + } + } + + pub fn is_search(&self) -> bool { + matches!(self, Path::PathSearch(_)) + } + + pub fn is_interpolatable(&self) -> bool { + !self.is_search() + } +} + +#[cfg(test)] +mod tests { + use rowan::ast::AstNode; + + use super::InterpolPart; + use crate::{ + ast::{self, Path}, + Root, + }; + + #[test] + fn test_path_types() { + // Absolute path + let inp = "/foo/bar"; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + if let ast::Expr::PathAbs(p) = expr { + let path = Path::cast(p.syntax().clone()).unwrap(); + assert!(path.is_interpolatable()); + assert!(!path.is_search()); + } + + // Search path + let inp = ""; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + if let ast::Expr::PathSearch(p) = expr { + let path = Path::cast(p.syntax().clone()).unwrap(); + assert!(!path.is_interpolatable()); + assert!(path.is_search()); + } + } + + #[test] + fn test_parts() { + // Test parts with absolute path + let inp = "/foo/bar"; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + if let ast::Expr::PathAbs(p) = expr { + let path = Path::cast(p.syntax().clone()).unwrap(); + + let parts = path.parts(); + assert_eq!(parts.len(), 1); + + match &parts[0] { + InterpolPart::Literal(content) => { + assert_eq!(content.text(), "/foo/bar"); + } + _ => panic!("Expected literal part"), + } + } + + // Test parts with interpolated path + let inp = r#"./a/${"hello"}"#; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + if let ast::Expr::PathRel(p) = expr { + let path = Path::cast(p.syntax().clone()).unwrap(); + + let parts = path.parts(); + assert_eq!(parts.len(), 2); + + match &parts[0] { + InterpolPart::Literal(content) => { + assert_eq!(content.text(), "./a/"); + } + _ => panic!("Expected literal part"), + } + + match &parts[1] { + InterpolPart::Interpolation(_) => {} // Success + _ => panic!("Expected interpolation part"), + } + } + + // Test parts with search path + let inp = ""; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + if let ast::Expr::PathSearch(p) = expr { + let path = Path::cast(p.syntax().clone()).unwrap(); + + let parts = path.parts(); + assert_eq!(parts.len(), 1); + + match &parts[0] { + InterpolPart::Literal(content) => { + assert_eq!(content.text(), ""); + } + _ => panic!("Expected literal part"), + } + } + } + + #[test] + fn direct_method_usage() { + // Test direct parts() method on PathAbs + let inp = "/foo/bar"; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + if let ast::Expr::PathAbs(p) = expr { + let parts = p.parts(); + assert_eq!(parts.len(), 1); + + match &parts[0] { + InterpolPart::Literal(content) => { + assert_eq!(content.text(), "/foo/bar"); + } + _ => panic!("Expected literal part"), + } + } + + // Test direct content() method on PathSearch + let inp = ""; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + if let ast::Expr::PathSearch(p) = expr { + let content = p.content().expect("Expected content"); + assert_eq!(content.text(), ""); + } + } +} diff --git a/third_party/crates/rnix-0.14.0/src/ast/str_util.rs b/third_party/crates/rnix-0.14.0/src/ast/str_util.rs new file mode 100644 index 0000000..2edb249 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/ast/str_util.rs @@ -0,0 +1,363 @@ +use crate::kinds::SyntaxKind::*; +use rowan::{ast::AstNode as OtherAstNode, NodeOrToken}; + +use crate::ast; + +use super::{support::children_tokens_u, AstToken, InterpolPart, StrContent}; + +impl ast::Str { + pub fn parts(&self) -> impl Iterator> { + self.syntax().children_with_tokens().filter_map(|child| match child { + NodeOrToken::Token(token) if token.kind() == TOKEN_STRING_CONTENT => { + Some(InterpolPart::Literal(StrContent::cast(token).unwrap())) + } + NodeOrToken::Token(token) => { + assert!(token.kind() == TOKEN_STRING_START || token.kind() == TOKEN_STRING_END); + None + } + NodeOrToken::Node(node) => { + assert_eq!(node.kind(), NODE_INTERPOL); + Some(InterpolPart::Interpolation(ast::Interpol::cast(node).unwrap())) + } + }) + } + + pub fn normalized_parts(&self) -> Vec> { + let multiline = children_tokens_u(self).next().is_some_and(|t| t.text() == "''"); + let mut is_first_literal = true; + let mut at_start_of_line = true; + let mut min_indent = 1000000; + let mut cur_indent = 0; + let mut n = 0; + let mut first_is_literal = false; + + let parts: Vec> = self.parts().collect(); + + if multiline { + for part in &parts { + match part { + InterpolPart::Interpolation(_) => { + if at_start_of_line { + at_start_of_line = false; + min_indent = min_indent.min(cur_indent); + } + n += 1; + } + InterpolPart::Literal(literal) => { + let mut token_text = literal.syntax().text(); + + if n == 0 { + first_is_literal = true; + } + + if is_first_literal && first_is_literal { + is_first_literal = false; + if let Some(p) = token_text.find('\n') { + if token_text[0..p].chars().all(|c| c == ' ') { + token_text = &token_text[p + 1..] + } + } + } + + for c in token_text.chars() { + if at_start_of_line { + if c == ' ' { + cur_indent += 1; + } else if c == '\n' { + cur_indent = 0; + } else { + at_start_of_line = false; + min_indent = min_indent.min(cur_indent); + } + } else if c == '\n' { + at_start_of_line = true; + cur_indent = 0; + } + } + + n += 1; + } + } + } + } + + let mut normalized_parts = Vec::new(); + let mut cur_dropped = 0; + let mut i = 0; + is_first_literal = true; + at_start_of_line = true; + + for part in parts { + match part { + InterpolPart::Interpolation(interpol) => { + at_start_of_line = false; + cur_dropped = 0; + normalized_parts.push(InterpolPart::Interpolation(interpol)); + i += 1; + } + InterpolPart::Literal(literal) => { + let mut token_text = literal.syntax().text(); + + if multiline { + if is_first_literal && first_is_literal { + is_first_literal = false; + if let Some(p) = token_text.find('\n') { + if token_text[0..p].chars().all(|c| c == ' ') { + token_text = &token_text[p + 1..]; + if token_text.is_empty() { + i += 1; + continue; + } + } + } + } + + let mut str = String::new(); + for c in token_text.chars() { + if at_start_of_line { + if c == ' ' { + if cur_dropped >= min_indent { + str.push(c); + } + cur_dropped += 1; + } else if c == '\n' { + cur_dropped = 0; + str.push(c); + } else { + at_start_of_line = false; + cur_dropped = 0; + str.push(c); + } + } else { + str.push(c); + if c == '\n' { + at_start_of_line = true; + } + } + } + + if i == n - 1 { + if let Some(p) = str.rfind('\n') { + if str[p + 1..].chars().all(|c| c == ' ') { + str.truncate(p + 1); + } + } + } + + normalized_parts.push(InterpolPart::Literal(unescape(&str, multiline))); + i += 1; + } else { + normalized_parts + .push(InterpolPart::Literal(unescape(token_text, multiline))); + } + } + } + } + + normalized_parts + } +} + +/// Interpret escape sequences in the nix string and return the converted value +pub fn unescape(input: &str, multiline: bool) -> String { + let mut output = String::new(); + let mut input = input.chars().peekable(); + loop { + match input.next() { + None => break, + Some('"') if !multiline => break, + Some('\\') if !multiline => match input.next() { + None => break, + Some('n') => output.push('\n'), + Some('r') => output.push('\r'), + Some('t') => output.push('\t'), + Some(c) => output.push(c), + }, + Some('\'') if multiline => match input.next() { + None => { + output.push('\''); + } + Some('\'') => match input.peek() { + Some('\'') => { + input.next().unwrap(); + output.push_str("''"); + } + Some('$') => { + input.next().unwrap(); + output.push('$'); + } + Some('\\') => { + input.next().unwrap(); + match input.next() { + None => break, + Some('n') => output.push('\n'), + Some('r') => output.push('\r'), + Some('t') => output.push('\t'), + Some(c) => output.push(c), + } + } + _ => break, + }, + Some(c) => { + output.push('\''); + output.push(c); + } + }, + Some(c) => output.push(c), + } + } + output +} + +#[cfg(test)] +mod tests { + use crate::Root; + + use super::*; + + #[test] + fn string_unescapes() { + assert_eq!(unescape(r#"Hello\n\"World\" :D"#, false), "Hello\n\"World\" :D"); + assert_eq!(unescape(r#"\"Hello\""#, false), "\"Hello\""); + + assert_eq!(unescape(r#"Hello''\n'''World''' :D"#, true), "Hello\n''World'' :D"); + assert_eq!(unescape(r#""Hello""#, true), "\"Hello\""); + } + #[test] + fn parts_leading_ws() { + let inp = "''\n hello\n world''"; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + match expr { + ast::Expr::Str(str) => { + assert_eq!( + str.normalized_parts(), + vec![InterpolPart::Literal("hello\nworld".to_string())] + ) + } + _ => unreachable!(), + } + } + #[test] + fn parts_trailing_ws_single_line() { + let inp = "''hello ''"; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + match expr { + ast::Expr::Str(str) => { + assert_eq!( + str.normalized_parts(), + vec![InterpolPart::Literal("hello ".to_string())] + ) + } + _ => unreachable!(), + } + } + #[test] + fn parts_trailing_ws_multiline() { + let inp = "''hello\n ''"; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + match expr { + ast::Expr::Str(str) => { + assert_eq!( + str.normalized_parts(), + vec![InterpolPart::Literal("hello\n".to_string())] + ) + } + _ => unreachable!(), + } + } + #[test] + fn parts() { + use crate::{NixLanguage, SyntaxNode}; + use rowan::{GreenNodeBuilder, Language}; + + fn string_node(content: &str) -> ast::Str { + let mut builder = GreenNodeBuilder::new(); + builder.start_node(NixLanguage::kind_to_raw(NODE_STRING)); + builder.token(NixLanguage::kind_to_raw(TOKEN_STRING_START), "''"); + builder.token(NixLanguage::kind_to_raw(TOKEN_STRING_CONTENT), content); + builder.token(NixLanguage::kind_to_raw(TOKEN_STRING_END), "''"); + builder.finish_node(); + + ast::Str::cast(SyntaxNode::new_root(builder.finish())).unwrap() + } + + let txtin = r#" + |trailing-whitespace + |trailing-whitespace + This is a multiline string :D + indented by two + \'\'\'\'\ + ''${ interpolation was escaped } + two single quotes: ''' + three single quotes: '''' + "# + .replace("|trailing-whitespace", ""); + + if let [InterpolPart::Literal(lit)] = + &ast::Str::normalized_parts(&string_node(txtin.as_str()))[..] + { + assert_eq!(lit, + // Get the below with nix repl + " \n \nThis is a multiline string :D\n indented by two\n\\'\\'\\'\\'\\\n${ interpolation was escaped }\ntwo single quotes: ''\nthree single quotes: '''\n" + ); + } else { + unreachable!(); + } + } + + #[test] + fn parts_ast() { + fn assert_eq_ast_ctn(it: &mut dyn Iterator>, x: &str) { + let tmp = it.next().expect("unexpected EOF"); + if let InterpolPart::Interpolation(astn) = tmp { + assert_eq!(astn.expr().unwrap().syntax().to_string(), x); + } else { + unreachable!("unexpected literal {:?}", tmp); + } + } + + let inp = r#"'' + + This version of Nixpkgs requires Nix >= ${requiredVersion}, please upgrade: + + - If you are running NixOS, `nixos-rebuild' can be used to upgrade your system. + + - Alternatively, with Nix > 2.0 `nix upgrade-nix' can be used to imperatively + upgrade Nix. You may use `nix-env --version' to check which version you have. + + - If you installed Nix using the install script (https://nixos.org/nix/install), + it is safe to upgrade by running it again: + + curl -L https://nixos.org/nix/install | sh + + For more information, please see the NixOS release notes at + https://nixos.org/nixos/manual or locally at + ${toString ./nixos/doc/manual/release-notes}. + + If you need further help, see https://nixos.org/nixos/support.html + ''"#; + let expr = Root::parse(inp).ok().unwrap().expr().unwrap(); + match expr { + ast::Expr::Str(s) => { + let mut it = s.normalized_parts().into_iter(); + assert_eq!( + it.next().unwrap(), + InterpolPart::Literal("\nThis version of Nixpkgs requires Nix >= ".to_string()) + ); + assert_eq_ast_ctn(&mut it, "requiredVersion"); + assert_eq!(it.next().unwrap(), InterpolPart::Literal( + ", please upgrade:\n\n- If you are running NixOS, `nixos-rebuild' can be used to upgrade your system.\n\n- Alternatively, with Nix > 2.0 `nix upgrade-nix' can be used to imperatively\n upgrade Nix. You may use `nix-env --version' to check which version you have.\n\n- If you installed Nix using the install script (https://nixos.org/nix/install),\n it is safe to upgrade by running it again:\n\n curl -L https://nixos.org/nix/install | sh\n\nFor more information, please see the NixOS release notes at\nhttps://nixos.org/nixos/manual or locally at\n".to_string() + )); + assert_eq_ast_ctn(&mut it, "toString ./nixos/doc/manual/release-notes"); + assert_eq!( + it.next().unwrap(), + InterpolPart::Literal( + ".\n\nIf you need further help, see https://nixos.org/nixos/support.html\n" + .to_string() + ) + ); + } + _ => unreachable!(), + } + } +} diff --git a/third_party/crates/rnix-0.14.0/src/ast/tokens.rs b/third_party/crates/rnix-0.14.0/src/ast/tokens.rs new file mode 100644 index 0000000..2d19ce0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/ast/tokens.rs @@ -0,0 +1,174 @@ +use core::num; + +use crate::{ + ast::AstToken, + SyntaxKind::{self, *}, + SyntaxToken, +}; + +macro_rules! token { + ( + #[from($kind:ident)] + $(#[$meta:meta])* + struct $name:ident; + ) => { + #[derive(Debug, Clone, PartialEq, Eq, Hash)] + $(#[$meta])* + pub struct $name(pub(super) SyntaxToken); + + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } + } + + impl AstToken for $name { + fn can_cast(kind: SyntaxKind) -> bool { + $kind == kind + } + + fn cast(from: SyntaxToken) -> Option { + if from.kind() == $kind { + Some(Self(from)) + } else { + None + } + } + + fn syntax(&self) -> &SyntaxToken { + &self.0 + } + } + }; +} + +token! { #[from(TOKEN_WHITESPACE)] struct Whitespace; } + +token! { #[from(TOKEN_COMMENT)] struct Comment; } + +impl Comment { + pub fn text(&self) -> &str { + let text = self.syntax().text(); + // Handle both "#..." and "/*...*/" comments. + match text.strip_prefix('#') { + Some(s) => s, + None => text.strip_prefix(r#"/*"#).unwrap().strip_suffix(r#"*/"#).unwrap(), + } + } +} + +#[cfg(test)] +mod tests { + use crate::ast; + use crate::match_ast; + use crate::Root; + + use super::*; + use rowan::ast::AstNode; + + #[test] + fn comment() { + let s = "# comment bruh +/* this is a multiline comment wow +asdfasdf +asdfasdf */ +1 + 1 +/* last one */ +"; + let comments: Vec = Root::parse(s) + .ok() + .unwrap() + .syntax() + .children_with_tokens() + .filter_map(|e| match e { + rowan::NodeOrToken::Token(token) => match_ast! { match token { + ast::Comment(it) => Some(it.text().to_string()), + _ => None, + }}, + rowan::NodeOrToken::Node(_) => None, + }) + .collect(); + let expected = vec![ + " comment bruh", + " this is a multiline comment wow\nasdfasdf\nasdfasdf ", + " last one ", + ]; + + assert_eq!(comments, expected); + } +} + +token! { #[from(TOKEN_FLOAT)] struct Float; } + +impl Float { + pub fn value(&self) -> Result { + self.syntax().text().parse() + } +} + +token! { #[from(TOKEN_INTEGER)] struct Integer; } + +impl Integer { + pub fn value(&self) -> Result { + self.syntax().text().parse() + } +} + +// A literal part of a path (absolute / relative / home / search) without +// distinguishing which concrete flavour it was taken from. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct PathContent(pub(super) SyntaxToken); + +impl PathContent { + /// Returns the path as a string + pub fn text(&self) -> &str { + self.syntax().text() + } + + /// Returns the kind of path token + pub fn path_kind(&self) -> SyntaxKind { + self.syntax().kind() + } + + /// Returns true if this is an absolute path + pub fn is_absolute(&self) -> bool { + self.path_kind() == TOKEN_PATH_ABS + } + + /// Returns true if this is a relative path + pub fn is_relative(&self) -> bool { + self.path_kind() == TOKEN_PATH_REL + } + + /// Returns true if this is a home-relative path + pub fn is_home(&self) -> bool { + self.path_kind() == TOKEN_PATH_HOME + } + + /// Returns true if this is a search path + pub fn is_search(&self) -> bool { + self.path_kind() == TOKEN_PATH_SEARCH + } +} + +impl AstToken for PathContent { + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, TOKEN_PATH_ABS | TOKEN_PATH_REL | TOKEN_PATH_HOME | TOKEN_PATH_SEARCH) + } + + fn cast(from: SyntaxToken) -> Option { + if Self::can_cast(from.kind()) { + Some(Self(from)) + } else { + None + } + } + + fn syntax(&self) -> &SyntaxToken { + &self.0 + } +} + +token! { #[from(TOKEN_STRING_CONTENT)] struct StrContent; } + +token! { #[from(TOKEN_URI)] struct Uri; } diff --git a/third_party/crates/rnix-0.14.0/src/kinds.rs b/third_party/crates/rnix-0.14.0/src/kinds.rs new file mode 100644 index 0000000..075c9eb --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/kinds.rs @@ -0,0 +1,285 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(u16)] +#[allow(non_camel_case_types)] +#[non_exhaustive] +pub enum SyntaxKind { + TOKEN_ADD, + TOKEN_AND_AND, + TOKEN_ASSIGN, + TOKEN_ASSERT, + TOKEN_AT, + TOKEN_COLON, + TOKEN_COMMA, + TOKEN_COMMENT, + TOKEN_CONCAT, + TOKEN_CUR_POS, + TOKEN_DIV, + TOKEN_DOT, + TOKEN_ELLIPSIS, + TOKEN_ELSE, + TOKEN_EQUAL, + TOKEN_ERROR, + TOKEN_FLOAT, + TOKEN_IDENT, + TOKEN_IF, + TOKEN_IMPLICATION, + TOKEN_IN, + TOKEN_INHERIT, + TOKEN_INTEGER, + TOKEN_INTERPOL_END, + TOKEN_INTERPOL_START, + TOKEN_INVERT, + TOKEN_L_BRACE, + TOKEN_L_BRACK, + TOKEN_L_PAREN, + TOKEN_LESS, + TOKEN_LESS_OR_EQ, + TOKEN_LET, + TOKEN_MORE, + TOKEN_MORE_OR_EQ, + TOKEN_MUL, + TOKEN_NOT_EQUAL, + TOKEN_OR, + TOKEN_OR_OR, + TOKEN_PATH_ABS, + TOKEN_PATH_HOME, + TOKEN_PATH_REL, + TOKEN_PATH_SEARCH, + TOKEN_PIPE_LEFT, + TOKEN_PIPE_RIGHT, + TOKEN_QUESTION, + TOKEN_R_BRACE, + TOKEN_R_BRACK, + TOKEN_R_PAREN, + TOKEN_REC, + TOKEN_SEMICOLON, + TOKEN_STRING_CONTENT, + TOKEN_STRING_END, + TOKEN_STRING_START, + TOKEN_SUB, + TOKEN_THEN, + TOKEN_UPDATE, + TOKEN_URI, + TOKEN_WHITESPACE, + TOKEN_WITH, + + NODE_APPLY, + NODE_ASSERT, + NODE_ATTR_SET, + NODE_ATTRPATH, + NODE_ATTRPATH_VALUE, + NODE_BIN_OP, + NODE_CUR_POS, + NODE_DYNAMIC, + NODE_ERROR, + // Attrpath existence check: foo ? bar.${baz}."bux" + NODE_HAS_ATTR, + NODE_IDENT, + NODE_IDENT_PARAM, + NODE_IF_ELSE, + NODE_INHERIT, + NODE_INHERIT_FROM, + NODE_INTERPOL, + NODE_LAMBDA, + // An old let { x = 92; body = x; } syntax + NODE_LEGACY_LET, + NODE_LET_IN, + NODE_LIST, + NODE_LITERAL, + NODE_PAREN, + NODE_PAT_BIND, + NODE_PAT_ENTRY, + NODE_PATTERN, + NODE_PATH_ABS, + NODE_PATH_HOME, + NODE_PATH_REL, + NODE_PATH_SEARCH, + NODE_ROOT, + NODE_SELECT, + NODE_STRING, + NODE_UNARY_OP, + NODE_WITH, +} +use SyntaxKind::*; + +/// Maximum valid discriminant value for SyntaxKind +pub(crate) const SYNTAX_KIND_MAX: u16 = NODE_WITH as u16; + +/// Error returned when parsing a string into a `SyntaxKind` fails. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ParseSyntaxKindError; + +impl std::fmt::Display for ParseSyntaxKindError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "invalid SyntaxKind") + } +} + +impl std::error::Error for ParseSyntaxKindError {} + +impl std::str::FromStr for SyntaxKind { + type Err = ParseSyntaxKindError; + + fn from_str(s: &str) -> Result { + match s { + "TOKEN_ADD" => Ok(TOKEN_ADD), + "TOKEN_AND_AND" => Ok(TOKEN_AND_AND), + "TOKEN_ASSIGN" => Ok(TOKEN_ASSIGN), + "TOKEN_ASSERT" => Ok(TOKEN_ASSERT), + "TOKEN_AT" => Ok(TOKEN_AT), + "TOKEN_COLON" => Ok(TOKEN_COLON), + "TOKEN_COMMA" => Ok(TOKEN_COMMA), + "TOKEN_COMMENT" => Ok(TOKEN_COMMENT), + "TOKEN_CONCAT" => Ok(TOKEN_CONCAT), + "TOKEN_CUR_POS" => Ok(TOKEN_CUR_POS), + "TOKEN_DIV" => Ok(TOKEN_DIV), + "TOKEN_DOT" => Ok(TOKEN_DOT), + "TOKEN_ELLIPSIS" => Ok(TOKEN_ELLIPSIS), + "TOKEN_ELSE" => Ok(TOKEN_ELSE), + "TOKEN_EQUAL" => Ok(TOKEN_EQUAL), + "TOKEN_ERROR" => Ok(TOKEN_ERROR), + "TOKEN_FLOAT" => Ok(TOKEN_FLOAT), + "TOKEN_IDENT" => Ok(TOKEN_IDENT), + "TOKEN_IF" => Ok(TOKEN_IF), + "TOKEN_IMPLICATION" => Ok(TOKEN_IMPLICATION), + "TOKEN_IN" => Ok(TOKEN_IN), + "TOKEN_INHERIT" => Ok(TOKEN_INHERIT), + "TOKEN_INTEGER" => Ok(TOKEN_INTEGER), + "TOKEN_INTERPOL_END" => Ok(TOKEN_INTERPOL_END), + "TOKEN_INTERPOL_START" => Ok(TOKEN_INTERPOL_START), + "TOKEN_INVERT" => Ok(TOKEN_INVERT), + "TOKEN_L_BRACE" => Ok(TOKEN_L_BRACE), + "TOKEN_L_BRACK" => Ok(TOKEN_L_BRACK), + "TOKEN_L_PAREN" => Ok(TOKEN_L_PAREN), + "TOKEN_LESS" => Ok(TOKEN_LESS), + "TOKEN_LESS_OR_EQ" => Ok(TOKEN_LESS_OR_EQ), + "TOKEN_LET" => Ok(TOKEN_LET), + "TOKEN_MORE" => Ok(TOKEN_MORE), + "TOKEN_MORE_OR_EQ" => Ok(TOKEN_MORE_OR_EQ), + "TOKEN_MUL" => Ok(TOKEN_MUL), + "TOKEN_NOT_EQUAL" => Ok(TOKEN_NOT_EQUAL), + "TOKEN_OR" => Ok(TOKEN_OR), + "TOKEN_OR_OR" => Ok(TOKEN_OR_OR), + "TOKEN_PATH_ABS" => Ok(TOKEN_PATH_ABS), + "TOKEN_PATH_HOME" => Ok(TOKEN_PATH_HOME), + "TOKEN_PATH_REL" => Ok(TOKEN_PATH_REL), + "TOKEN_PATH_SEARCH" => Ok(TOKEN_PATH_SEARCH), + "TOKEN_PIPE_LEFT" => Ok(TOKEN_PIPE_LEFT), + "TOKEN_PIPE_RIGHT" => Ok(TOKEN_PIPE_RIGHT), + "TOKEN_QUESTION" => Ok(TOKEN_QUESTION), + "TOKEN_R_BRACE" => Ok(TOKEN_R_BRACE), + "TOKEN_R_BRACK" => Ok(TOKEN_R_BRACK), + "TOKEN_R_PAREN" => Ok(TOKEN_R_PAREN), + "TOKEN_REC" => Ok(TOKEN_REC), + "TOKEN_SEMICOLON" => Ok(TOKEN_SEMICOLON), + "TOKEN_STRING_CONTENT" => Ok(TOKEN_STRING_CONTENT), + "TOKEN_STRING_END" => Ok(TOKEN_STRING_END), + "TOKEN_STRING_START" => Ok(TOKEN_STRING_START), + "TOKEN_SUB" => Ok(TOKEN_SUB), + "TOKEN_THEN" => Ok(TOKEN_THEN), + "TOKEN_UPDATE" => Ok(TOKEN_UPDATE), + "TOKEN_URI" => Ok(TOKEN_URI), + "TOKEN_WHITESPACE" => Ok(TOKEN_WHITESPACE), + "TOKEN_WITH" => Ok(TOKEN_WITH), + + "NODE_APPLY" => Ok(NODE_APPLY), + "NODE_ASSERT" => Ok(NODE_ASSERT), + "NODE_ATTR_SET" => Ok(NODE_ATTR_SET), + "NODE_ATTRPATH" => Ok(NODE_ATTRPATH), + "NODE_ATTRPATH_VALUE" => Ok(NODE_ATTRPATH_VALUE), + "NODE_BIN_OP" => Ok(NODE_BIN_OP), + "NODE_CUR_POS" => Ok(NODE_CUR_POS), + "NODE_DYNAMIC" => Ok(NODE_DYNAMIC), + "NODE_ERROR" => Ok(NODE_ERROR), + "NODE_HAS_ATTR" => Ok(NODE_HAS_ATTR), + "NODE_IDENT" => Ok(NODE_IDENT), + "NODE_IDENT_PARAM" => Ok(NODE_IDENT_PARAM), + "NODE_IF_ELSE" => Ok(NODE_IF_ELSE), + "NODE_INHERIT" => Ok(NODE_INHERIT), + "NODE_INHERIT_FROM" => Ok(NODE_INHERIT_FROM), + "NODE_INTERPOL" => Ok(NODE_INTERPOL), + "NODE_LAMBDA" => Ok(NODE_LAMBDA), + "NODE_LEGACY_LET" => Ok(NODE_LEGACY_LET), + "NODE_LET_IN" => Ok(NODE_LET_IN), + "NODE_LIST" => Ok(NODE_LIST), + "NODE_LITERAL" => Ok(NODE_LITERAL), + "NODE_PAREN" => Ok(NODE_PAREN), + "NODE_PAT_BIND" => Ok(NODE_PAT_BIND), + "NODE_PAT_ENTRY" => Ok(NODE_PAT_ENTRY), + "NODE_PATTERN" => Ok(NODE_PATTERN), + "NODE_PATH_ABS" => Ok(NODE_PATH_ABS), + "NODE_PATH_HOME" => Ok(NODE_PATH_HOME), + "NODE_PATH_REL" => Ok(NODE_PATH_REL), + "NODE_PATH_SEARCH" => Ok(NODE_PATH_SEARCH), + "NODE_ROOT" => Ok(NODE_ROOT), + "NODE_SELECT" => Ok(NODE_SELECT), + "NODE_STRING" => Ok(NODE_STRING), + "NODE_UNARY_OP" => Ok(NODE_UNARY_OP), + "NODE_WITH" => Ok(NODE_WITH), + + _ => Err(ParseSyntaxKindError), + } + } +} + +impl SyntaxKind { + /// Returns true if this token is a literal, such as an integer or a string + pub fn is_literal(self) -> bool { + matches!( + self, + TOKEN_FLOAT + | TOKEN_INTEGER + | TOKEN_PATH_ABS + | TOKEN_PATH_REL + | TOKEN_PATH_HOME + | TOKEN_PATH_SEARCH + | TOKEN_URI + ) + } + + /// Returns true if this token should be used as a function argument. + /// ```ignore + /// Example: + /// add 1 2 + 3 + /// ^ ^ ^ ^ + /// | | | +- false + /// | | +- true + /// | +- true + /// +- true + /// ``` + pub fn is_fn_arg(self) -> bool { + match self { + // NB: the tokenizer always emits TOKEN_IDENT for __curPos; + // TOKEN_CUR_POS is included for completeness but cannot + // currently be produced by the tokenizer. + TOKEN_REC | TOKEN_L_BRACE | TOKEN_L_BRACK | TOKEN_L_PAREN | TOKEN_STRING_START + | TOKEN_IDENT | TOKEN_CUR_POS => true, + _ => self.is_literal(), + } + } + /// Returns true if this token is a comment, whitespace, or similar, and + /// should be skipped over by the parser. + pub fn is_trivia(self) -> bool { + matches!(self, TOKEN_COMMENT | TOKEN_WHITESPACE) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::str::FromStr; + + #[test] + fn from_str_valid() { + assert_eq!(SyntaxKind::from_str("TOKEN_COMMENT").unwrap(), TOKEN_COMMENT); + assert_eq!(SyntaxKind::from_str("NODE_ROOT").unwrap(), NODE_ROOT); + assert_eq!(SyntaxKind::from_str("NODE_HAS_ATTR").unwrap(), NODE_HAS_ATTR); + } + + #[test] + fn from_str_invalid() { + assert!(SyntaxKind::from_str("INVALID").is_err()); + assert!(SyntaxKind::from_str("").is_err()); + assert!(SyntaxKind::from_str("token_comment").is_err()); // case sensitive + } +} diff --git a/third_party/crates/rnix-0.14.0/src/lib.rs b/third_party/crates/rnix-0.14.0/src/lib.rs new file mode 100644 index 0000000..23e40ab --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/lib.rs @@ -0,0 +1,111 @@ +#[macro_use] +mod macros; +pub mod ast; +mod kinds; +mod parser; +#[cfg(test)] +mod tests; +mod token_set; +mod tokenizer; + +use std::marker::PhantomData; + +use self::kinds::SYNTAX_KIND_MAX; +pub use self::{kinds::ParseSyntaxKindError, kinds::SyntaxKind, tokenizer::tokenize}; + +use ast::AstNode; +pub use parser::ParseError; +use rowan::GreenNode; +pub use rowan::{NodeOrToken, TextRange, TextSize, TokenAtOffset, WalkEvent}; +pub(crate) use token_set::TokenSet; +pub use tokenizer::Token; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum NixLanguage {} + +impl rowan::Language for NixLanguage { + type Kind = SyntaxKind; + fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind { + let discriminant: u16 = raw.0; + assert!(discriminant <= SYNTAX_KIND_MAX); + unsafe { std::mem::transmute::(discriminant) } + } + fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind { + rowan::SyntaxKind(kind as u16) + } +} + +pub type SyntaxNode = rowan::SyntaxNode; +pub type SyntaxToken = rowan::SyntaxToken; +pub type SyntaxElement = rowan::NodeOrToken; +pub type SyntaxElementChildren = rowan::SyntaxElementChildren; +pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren; + +pub use ast::Root; + +impl Root { + pub fn parse(s: &str) -> Parse { + let (green, errors) = parser::parse(tokenize(s)); + Parse { green, errors, _ty: PhantomData } + } +} + +/// The result of a parse +#[derive(Clone)] +pub struct Parse { + green: GreenNode, + errors: Vec, + _ty: PhantomData T>, +} + +impl Parse { + pub fn syntax(&self) -> SyntaxNode { + SyntaxNode::new_root(self.green.clone()) + } +} + +impl Parse { + pub fn tree(&self) -> T { + T::cast(self.syntax()).unwrap() + } + + /// Return all errors in the tree, if any + pub fn errors(&self) -> &[ParseError] { + &self.errors + } + + /// Either return the first error in the tree, or if there are none return self + pub fn ok(self) -> Result { + if let Some(err) = self.errors().first() { + return Err(err.clone()); + } + Ok(self.tree()) + } +} + +/// Matches a `SyntaxNode` against an `ast` type. +/// +/// # Example: +/// +/// ```ignore +/// match_ast! { +/// match node { +/// ast::Apply(it) => { ... }, +/// ast::Assert(it) => { ... }, +/// ast::IfElse(it) => { ... }, +/// _ => None, +/// } +/// } +/// ``` +#[macro_export] +macro_rules! match_ast { + (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; + + (match ($node:expr) { + $( ast::$ast:ident($it:pat) => $res:expr, )* + _ => $catch_all:expr $(,)? + }) => {{ + $( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )* + { $catch_all } + }}; +} diff --git a/third_party/crates/rnix-0.14.0/src/macros.rs b/third_party/crates/rnix-0.14.0/src/macros.rs new file mode 100644 index 0000000..03a5dda --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/macros.rs @@ -0,0 +1,52 @@ +#[macro_export] +#[rustfmt::skip] +macro_rules! T { + (assert) => ($crate::SyntaxKind::TOKEN_ASSERT); + (else) => ($crate::SyntaxKind::TOKEN_ELSE); + (if) => ($crate::SyntaxKind::TOKEN_IF); + (in) => ($crate::SyntaxKind::TOKEN_IN); + (inherit) => ($crate::SyntaxKind::TOKEN_INHERIT); + (let) => ($crate::SyntaxKind::TOKEN_LET); + (or) => ($crate::SyntaxKind::TOKEN_OR); + (rec) => ($crate::SyntaxKind::TOKEN_REC); + (then) => ($crate::SyntaxKind::TOKEN_THEN); + (with) => ($crate::SyntaxKind::TOKEN_WITH); + (__curPos) => ($crate::SyntaxKind::TOKEN_CUR_POS); + + ('{') => ($crate::SyntaxKind::TOKEN_L_BRACE); + ('}') => ($crate::SyntaxKind::TOKEN_R_BRACE); + ('[') => ($crate::SyntaxKind::TOKEN_L_BRACK); + (']') => ($crate::SyntaxKind::TOKEN_R_BRACK); + ('(') => ($crate::SyntaxKind::TOKEN_L_PAREN); + (')') => ($crate::SyntaxKind::TOKEN_R_PAREN); + + (=) => ($crate::SyntaxKind::TOKEN_ASSIGN); + (@) => ($crate::SyntaxKind::TOKEN_AT); + (:) => ($crate::SyntaxKind::TOKEN_COLON); + (,) => ($crate::SyntaxKind::TOKEN_COMMA); + (.) => ($crate::SyntaxKind::TOKEN_DOT); + (...) => ($crate::SyntaxKind::TOKEN_ELLIPSIS); + (?) => ($crate::SyntaxKind::TOKEN_QUESTION); + (;) => ($crate::SyntaxKind::TOKEN_SEMICOLON); + (++) => ($crate::SyntaxKind::TOKEN_CONCAT); + (!) => ($crate::SyntaxKind::TOKEN_INVERT); + ("//") => ($crate::SyntaxKind::TOKEN_UPDATE); + + (+) => ($crate::SyntaxKind::TOKEN_ADD); + (-) => ($crate::SyntaxKind::TOKEN_SUB); + (*) => ($crate::SyntaxKind::TOKEN_MUL); + (/) => ($crate::SyntaxKind::TOKEN_DIV); + + (&&) => ($crate::SyntaxKind::TOKEN_AND_AND); + (==) => ($crate::SyntaxKind::TOKEN_EQUAL); + (->) => ($crate::SyntaxKind::TOKEN_IMPLICATION); + (<) => ($crate::SyntaxKind::TOKEN_LESS); + (<=) => ($crate::SyntaxKind::TOKEN_LESS_OR_EQ); + (>) => ($crate::SyntaxKind::TOKEN_MORE); + (>=) => ($crate::SyntaxKind::TOKEN_MORE_OR_EQ); + (!=) => ($crate::SyntaxKind::TOKEN_NOT_EQUAL); + (||) => ($crate::SyntaxKind::TOKEN_OR_OR); + ("|>") => ($crate::SyntaxKind::TOKEN_PIPE_RIGHT); + ("<|") => ($crate::SyntaxKind::TOKEN_PIPE_LEFT); + ($kind:ident) => ($crate::SyntaxKind::$kind); +} diff --git a/third_party/crates/rnix-0.14.0/src/parser.rs b/third_party/crates/rnix-0.14.0/src/parser.rs new file mode 100644 index 0000000..bff524b --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/parser.rs @@ -0,0 +1,834 @@ +//! The parser: turns a series of tokens into an AST + +use std::{collections::VecDeque, fmt}; + +use rowan::{Checkpoint, GreenNode, GreenNodeBuilder, Language, TextRange, TextSize}; + +use crate::{ + tokenizer::Token, + NixLanguage, + SyntaxKind::{self, *}, + TokenSet, +}; + +/// An error that occurred during parsing +#[derive(Clone, Debug, PartialEq)] +#[non_exhaustive] +pub enum ParseError { + /// Unexpected is used when the cause cannot be specified further + Unexpected(TextRange), + /// UnexpectedExtra is used when there are additional tokens to the root in the tree + UnexpectedExtra(TextRange), + /// UnexpectedWanted is used when specific tokens are expected, but different one is found + UnexpectedWanted(SyntaxKind, TextRange, Box<[SyntaxKind]>), + /// UnexpectedDoubleBind is used when a pattern is bound twice + UnexpectedDoubleBind(TextRange), + /// UnexpectedEOF is used when the end of file is reached, while tokens are still expected + UnexpectedEOF, + /// UnexpectedEOFWanted is used when specific tokens are expected, but the end of file is reached + UnexpectedEOFWanted(Box<[SyntaxKind]>), + /// DuplicatedArgs is used when formal arguments are duplicated, e.g. `{ a, a }` + DuplicatedArgs(TextRange, String), + /// RecursionLimitExceeded is used when we're unable to parse further due to likely being close to + /// a stack overflow. + RecursionLimitExceeded, +} + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ParseError::Unexpected(range) => { + write!( + f, + "error node at {}..{}", + usize::from(range.start()), + usize::from(range.end()) + ) + } + ParseError::UnexpectedExtra(range) => { + write!( + f, + "unexpected token at {}..{}", + usize::from(range.start()), + usize::from(range.end()) + ) + } + ParseError::UnexpectedWanted(got, range, kinds) => write!( + f, + "unexpected {:?} at {}..{}, wanted any of {:?}", + got, + usize::from(range.start()), + usize::from(range.end()), + kinds + ), + ParseError::UnexpectedDoubleBind(range) => { + write!( + f, + "unexpected double bind at {}..{}", + usize::from(range.start()), + usize::from(range.end()) + ) + } + ParseError::UnexpectedEOF => write!(f, "unexpected end of file"), + ParseError::UnexpectedEOFWanted(kinds) => { + write!(f, "unexpected end of file, wanted any of {:?}", kinds) + } + ParseError::DuplicatedArgs(range, ident) => { + write!( + f, + "argument `{}` is duplicated in {}..{}", + ident, + usize::from(range.start()), + usize::from(range.end()) + ) + } + ParseError::RecursionLimitExceeded => write!(f, "recursion limit exceeded"), + } + } +} + +impl std::error::Error for ParseError {} + +struct Parser<'a, I> +where + I: Iterator>, +{ + builder: GreenNodeBuilder<'static>, + errors: Vec, + + trivia_buffer: Vec>, + buffer: VecDeque>, + iter: I, + consumed: TextSize, + + // Recursion depth, used for avoiding stack overflows. This may be incremented + // by any method as long as it is decremented when that method returns. + depth: u32, +} +impl<'a, I> Parser<'a, I> +where + I: Iterator>, +{ + fn new(iter: I) -> Self { + Self { + builder: GreenNodeBuilder::new(), + errors: Vec::new(), + + trivia_buffer: Vec::with_capacity(1), + buffer: VecDeque::with_capacity(1), + iter, + consumed: TextSize::from(0), + + depth: 0, + } + } + + fn get_text_position(&self) -> TextSize { + self.consumed + } + + fn peek_raw(&mut self) -> Option<&Token<'a>> { + if self.buffer.is_empty() { + if let Some(token) = self.iter.next() { + self.buffer.push_back(token); + } + } + self.buffer.front() + } + fn drain_trivia_buffer(&mut self) { + for (t, s) in self.trivia_buffer.drain(..) { + self.consumed += TextSize::of(s); + self.builder.token(NixLanguage::kind_to_raw(t), s); + } + } + fn eat_trivia(&mut self) { + self.peek(); + self.drain_trivia_buffer(); + } + fn start_node(&mut self, kind: SyntaxKind) { + self.eat_trivia(); + self.builder.start_node(NixLanguage::kind_to_raw(kind)); + } + fn checkpoint(&mut self) -> Checkpoint { + self.eat_trivia(); + self.builder.checkpoint() + } + fn start_node_at(&mut self, checkpoint: Checkpoint, kind: SyntaxKind) { + self.builder.start_node_at(checkpoint, NixLanguage::kind_to_raw(kind)); + } + fn finish_node(&mut self) { + self.builder.finish_node(); + } + fn start_error_node(&mut self) -> TextSize { + self.start_node(NODE_ERROR); + self.get_text_position() + } + fn finish_error_node(&mut self) -> TextSize { + self.finish_node(); + self.get_text_position() + } + fn bump(&mut self) { + match self.try_next() { + Some((token, s)) => { + if token.is_trivia() { + self.trivia_buffer.push((token, s)) + } else { + self.drain_trivia_buffer(); + self.manual_bump(s, token); + } + } + None => self.errors.push(ParseError::UnexpectedEOF), + } + } + fn try_next(&mut self) -> Option> { + self.buffer.pop_front().or_else(|| self.iter.next()) + } + fn manual_bump(&mut self, s: &str, token: SyntaxKind) { + self.consumed += TextSize::of(s); + self.builder.token(NixLanguage::kind_to_raw(token), s) + } + fn peek(&mut self) -> Option { + while self.peek_raw().map(|&(t, _)| t.is_trivia()).unwrap_or(false) { + self.bump(); + } + self.peek_ahead(0) + } + fn peek_ahead(&mut self, n: usize) -> Option { + let mut non_trivia_seen = 0; + let mut cursor = 0; + loop { + if self.buffer.len() <= cursor { + self.buffer.push_back(self.iter.next()?); + } + let kind = self.buffer[cursor].0; + cursor += 1; + if !kind.is_trivia() { + if non_trivia_seen == n { + return Some(kind); + } + non_trivia_seen += 1; + } + } + } + fn expect_peek_any(&mut self, allowed_slice: &[SyntaxKind]) -> Option { + let allowed = TokenSet::from_slice(allowed_slice); + + let next = match self.peek() { + None => None, + Some(kind) if allowed.contains(kind) => Some(kind), + Some(kind) => { + let start = self.start_error_node(); + loop { + self.bump(); + if self.peek().map(|kind| allowed.contains(kind)).unwrap_or(true) { + break; + } + } + let end = self.finish_error_node(); + self.errors.push(ParseError::UnexpectedWanted( + kind, + TextRange::new(start, end), + allowed_slice.to_vec().into_boxed_slice(), + )); + + self.peek() + } + }; + if next.is_none() { + self.errors + .push(ParseError::UnexpectedEOFWanted(allowed_slice.to_vec().into_boxed_slice())); + } + next + } + fn expect(&mut self, expected: SyntaxKind) { + if self.expect_peek_any(&[expected]).is_some() { + self.bump(); + } + } + + fn expect_ident(&mut self) { + if self.expect_peek_any(&[TOKEN_IDENT]).is_some() { + self.start_node(NODE_IDENT); + self.bump(); + self.finish_node() + } + } + + fn parse_dynamic(&mut self) { + self.start_node(NODE_DYNAMIC); + self.bump(); + while self.peek().map(|t| t != TOKEN_INTERPOL_END).unwrap_or(false) { + self.parse_expr(); + } + self.bump(); + self.finish_node(); + } + + fn parse_string(&mut self) { + self.start_node(NODE_STRING); + self.expect(TOKEN_STRING_START); + + loop { + match self.expect_peek_any(&[ + TOKEN_STRING_END, + TOKEN_STRING_CONTENT, + TOKEN_INTERPOL_START, + ]) { + Some(TOKEN_STRING_CONTENT) => self.bump(), + Some(TOKEN_INTERPOL_START) => { + self.start_node(NODE_INTERPOL); + self.bump(); + self.parse_expr(); + self.expect(TOKEN_INTERPOL_END); + self.finish_node(); + } + // handled by expect_peek_any + _ => break, + } + } + self.expect(TOKEN_STRING_END); + + self.finish_node(); + } + fn parse_attr(&mut self) { + match self.peek() { + Some(TOKEN_INTERPOL_START) => self.parse_dynamic(), + Some(TOKEN_STRING_START) => self.parse_string(), + _ => { + // NB: the tokenizer always emits TOKEN_IDENT for __curPos; + // TOKEN_CUR_POS is included for completeness but cannot + // currently be produced by the tokenizer. + if self.expect_peek_any(&[TOKEN_IDENT, TOKEN_OR, TOKEN_CUR_POS]).is_some() { + self.start_node(NODE_IDENT); + let (_, s) = self.try_next().unwrap(); + self.manual_bump(s, TOKEN_IDENT); + self.finish_node() + } + } + } + } + fn parse_attrpath(&mut self) { + self.start_node(NODE_ATTRPATH); + loop { + self.parse_attr(); + + if self.peek() == Some(T![.]) { + self.bump(); + } else { + break; + } + } + self.finish_node(); + } + fn parse_pattern(&mut self, bound: bool) { + if self.peek().map(|t| t == T!['}']).unwrap_or(true) { + self.bump(); + } else { + loop { + match self.expect_peek_any(&[T!['}'], T![...], TOKEN_IDENT]) { + Some(T!['}']) => { + self.bump(); + break; + } + Some(T![...]) => { + self.bump(); + self.expect(T!['}']); + break; + } + Some(TOKEN_IDENT) => { + self.start_node(NODE_PAT_ENTRY); + self.expect_ident(); + if let Some(T![?]) = self.peek() { + self.bump(); + self.parse_expr(); + } + self.finish_node(); + match self.peek() { + Some(T![,]) => self.bump(), + _ => { + self.expect(T!['}']); + break; + } + } + } + // handled by expect_peek_any + _ => break, + } + } + } + + if self.peek() == Some(T![@]) { + let kind = if bound { NODE_ERROR } else { NODE_PAT_BIND }; + self.start_node(kind); + let start = self.get_text_position(); + self.bump(); + self.expect_ident(); + let end = self.finish_error_node(); + if bound { + self.errors.push(ParseError::UnexpectedDoubleBind(TextRange::new(start, end))); + } + } + } + fn parse_set(&mut self, until: SyntaxKind) { + loop { + match self.peek() { + None => break, + token if token == Some(until) => break, + Some(T![inherit]) => { + self.start_node(NODE_INHERIT); + self.bump(); + + if self.peek() == Some(T!['(']) { + self.start_node(NODE_INHERIT_FROM); + self.bump(); + self.parse_expr(); + self.expect(T![')']); + self.finish_node(); + } + + loop { + match self.peek() { + Some(t) if t != T![;] => { + self.parse_attr(); + } + Some(_) => { + break; + } + None => { + self.errors.push(ParseError::UnexpectedEOF); + break; + } + } + } + + self.expect(T![;]); + self.finish_node(); + } + Some(_) => { + self.start_node(NODE_ATTRPATH_VALUE); + self.parse_attrpath(); + self.expect(T![=]); + self.parse_expr(); + self.expect(T![;]); + self.finish_node(); + } + } + } + self.bump(); // the final close, like '}' + } + + fn parse_simple(&mut self) -> Checkpoint { + let peek = match self.peek() { + Some(it) => it, + None => { + self.errors.push(ParseError::UnexpectedEOF); + // NB: we don't use `self.checkpoint()` here in order to avoid + // eating the whitespace. The actual checkpoint doesn't matter + // in this case and, ideally, should be returning `None`, but + // that makes code slightly more complex for little real + // benefit. + return self.builder.checkpoint(); + } + }; + let checkpoint = self.checkpoint(); + match peek { + T!['('] => { + self.start_node(NODE_PAREN); + self.bump(); + self.parse_expr(); + self.bump(); + self.finish_node(); + } + T![rec] => { + self.start_node(NODE_ATTR_SET); + self.bump(); + self.expect(T!['{']); + self.parse_set(T!['}']); + self.finish_node(); + } + T!['{'] => { + // Do a lookahead: + let mut peek = [None, None]; + for i in &mut peek { + let mut token; + *i = loop { + token = self.iter.next(); + let kind = token.as_ref().map(|&(t, _)| t); + if let Some(token) = token { + self.buffer.push_back(token); + } + if kind.map(|t| !t.is_trivia()).unwrap_or(true) { + break kind; + } + }; + } + + match peek { + [Some(TOKEN_IDENT), Some(T![,])] + | [Some(TOKEN_IDENT), Some(T![?])] + | [Some(TOKEN_IDENT), Some(T!['}'])] + | [Some(T![...]), Some(T!['}'])] + | [Some(T!['}']), Some(T![:])] + | [Some(T!['}']), Some(T![@])] => { + // This looks like a pattern + self.start_node(NODE_LAMBDA); + + self.start_node(NODE_PATTERN); + self.bump(); + self.parse_pattern(false); + self.finish_node(); + + self.expect(T![:]); + self.parse_expr(); + + self.finish_node(); + } + _ => { + // This looks like a set + self.start_node(NODE_ATTR_SET); + self.bump(); + self.parse_set(T!['}']); + self.finish_node(); + } + } + } + T!['['] => { + self.start_node(NODE_LIST); + self.bump(); + while self.peek().map(|t| t != T![']']).unwrap_or(false) { + self.parse_simple(); + } + self.bump(); + self.finish_node(); + } + TOKEN_STRING_START => self.parse_string(), + TOKEN_PATH_ABS | TOKEN_PATH_REL | TOKEN_PATH_HOME | TOKEN_PATH_SEARCH => { + let node_kind = match self.peek().unwrap() { + TOKEN_PATH_ABS => NODE_PATH_ABS, + TOKEN_PATH_REL => NODE_PATH_REL, + TOKEN_PATH_HOME => NODE_PATH_HOME, + TOKEN_PATH_SEARCH => NODE_PATH_SEARCH, + _ => unreachable!(), + }; + self.start_node(node_kind); + self.bump(); + + // Search paths () don't support interpolation + let is_search_path = node_kind == NODE_PATH_SEARCH; + let is_complex_path = !is_search_path && self.peek() == Some(TOKEN_INTERPOL_START); + + if is_complex_path { + loop { + match self.peek_raw().map(|(t, _)| t) { + Some(TOKEN_PATH_ABS) | Some(TOKEN_PATH_REL) | Some(TOKEN_PATH_HOME) => { + self.bump() + } + Some(TOKEN_INTERPOL_START) => { + self.start_node(NODE_INTERPOL); + self.bump(); + self.parse_expr(); + self.expect(TOKEN_INTERPOL_END); + self.finish_node(); + } + _ => break, + } + } + } + self.finish_node(); + } + t if t.is_literal() => { + self.start_node(NODE_LITERAL); + self.bump(); + self.finish_node(); + } + TOKEN_IDENT => { + let ident = self.peek_raw().map(|&(_, s)| s); + + match self.peek_ahead(1) { + Some(T![:]) => { + self.expect_ident(); + + self.start_node_at(checkpoint, NODE_LAMBDA); + self.start_node_at(checkpoint, NODE_IDENT_PARAM); + self.finish_node(); + self.expect(T![:]); + self.parse_expr(); + self.finish_node(); + } + Some(T![@]) => { + self.expect_ident(); + + self.start_node_at(checkpoint, NODE_LAMBDA); + self.start_node_at(checkpoint, NODE_PATTERN); + self.start_node_at(checkpoint, NODE_PAT_BIND); + self.expect(T![@]); + self.finish_node(); // PatBind + + self.expect(T!['{']); + self.parse_pattern(true); + self.finish_node(); // Pattern + + self.expect(T![:]); + self.parse_expr(); + self.finish_node(); // Lambda + } + _ if ident == Some("__curPos") => { + self.start_node(NODE_CUR_POS); + let (_, s) = self.try_next().unwrap(); + self.manual_bump(s, TOKEN_CUR_POS); + self.finish_node(); + } + _ => self.expect_ident(), + } + } + kind => { + let start = self.start_error_node(); + self.bump(); + let end = self.finish_error_node(); + self.errors.push(ParseError::UnexpectedWanted( + kind, + TextRange::new(start, end), + [T!['('], T![rec], T!['{'], T!['['], TOKEN_STRING_START, TOKEN_IDENT] + .to_vec() + .into_boxed_slice(), + )); + } + }; + + if self.peek() == Some(T![.]) { + self.start_node_at(checkpoint, NODE_SELECT); + self.bump(); + self.parse_attrpath(); + if self.peek() == Some(T![or]) { + self.bump(); + self.parse_simple(); + } + self.finish_node(); + + // This seems weird, but it matches Nix's behavior. + // If there is no "." but a "or" immediately followed a primary expression, + // we construct a application node, with "or" parsed as an identifier, + // ignoring the associativity of ancestor applications. + // Eg. + // "a b or c" => "((a (b or)) c)" + // "or a" => fail + } else if self.peek() == Some(T![or]) { + self.start_node_at(checkpoint, NODE_APPLY); + self.start_node(NODE_IDENT); + let (_, s) = self.try_next().unwrap(); + self.manual_bump(s, TOKEN_IDENT); + self.finish_node(); + self.finish_node(); + } + + checkpoint + } + fn parse_fn(&mut self) -> Checkpoint { + let checkpoint = self.parse_simple(); + + while self.peek().map(|t| t.is_fn_arg()).unwrap_or(false) { + self.start_node_at(checkpoint, NODE_APPLY); + self.parse_simple(); + self.finish_node(); + } + checkpoint + } + fn parse_negate(&mut self) -> Checkpoint { + if self.peek() == Some(T![-]) { + let checkpoint = self.checkpoint(); + self.start_node(NODE_UNARY_OP); + self.bump(); + self.parse_negate(); + self.finish_node(); + checkpoint + } else { + self.parse_fn() + } + } + fn parse_non_assoc(&mut self, next: fn(&mut Self) -> Checkpoint, ops: TokenSet) -> Checkpoint { + let checkpoint = next(self); + if self.peek().map(|t| ops.contains(t)).unwrap_or(false) { + self.start_node_at(checkpoint, NODE_BIN_OP); + self.bump(); + next(self); + self.finish_node(); + } + checkpoint + } + fn parse_left_assoc(&mut self, next: fn(&mut Self) -> Checkpoint, ops: TokenSet) -> Checkpoint { + let checkpoint = next(self); + while self.peek().map(|t| ops.contains(t)).unwrap_or(false) { + self.start_node_at(checkpoint, NODE_BIN_OP); + self.bump(); + next(self); + self.finish_node(); + } + checkpoint + } + fn parse_right_assoc( + &mut self, + next: fn(&mut Self) -> Checkpoint, + ops: TokenSet, + ) -> Checkpoint { + let checkpoint = next(self); + if self.peek().map(|t| ops.contains(t)).unwrap_or(false) { + self.start_node_at(checkpoint, NODE_BIN_OP); + self.bump(); + self.parse_right_assoc(next, ops); + self.finish_node(); + } + checkpoint + } + fn parse_hasattr(&mut self) -> Checkpoint { + let checkpoint = self.parse_negate(); + while self.peek().map(|t| t == T![?]).unwrap_or(false) { + self.start_node_at(checkpoint, NODE_HAS_ATTR); + self.bump(); + self.parse_attrpath(); + self.finish_node(); + } + checkpoint + } + fn parse_concat(&mut self) -> Checkpoint { + self.parse_right_assoc(Self::parse_hasattr, T![++] | ()) + } + fn parse_mul(&mut self) -> Checkpoint { + self.parse_left_assoc(Self::parse_concat, T![*] | T![/]) + } + fn parse_add(&mut self) -> Checkpoint { + self.parse_left_assoc(Self::parse_mul, T![+] | T![-]) + } + fn parse_invert(&mut self) -> Checkpoint { + if self.peek() == Some(TOKEN_INVERT) { + let checkpoint = self.checkpoint(); + self.start_node(NODE_UNARY_OP); + self.bump(); + self.parse_invert(); + self.finish_node(); + checkpoint + } else { + self.parse_add() + } + } + fn parse_merge(&mut self) -> Checkpoint { + self.parse_right_assoc(Self::parse_invert, T!["//"] | ()) + } + fn parse_compare(&mut self) -> Checkpoint { + self.parse_non_assoc(Self::parse_merge, T![<] | T![<=] | T![>] | T![>=]) + } + fn parse_equal(&mut self) -> Checkpoint { + self.parse_non_assoc(Self::parse_compare, T![==] | T![!=]) + } + fn parse_and(&mut self) -> Checkpoint { + self.parse_left_assoc(Self::parse_equal, T![&&] | ()) + } + fn parse_or(&mut self) -> Checkpoint { + self.parse_left_assoc(Self::parse_and, T![||] | ()) + } + fn parse_implication(&mut self) -> Checkpoint { + self.parse_right_assoc(Self::parse_or, T![->] | ()) + } + #[inline(always)] + fn parse_math(&mut self) -> Checkpoint { + // Always point this to the lowest-level math function there is + self.parse_implication() + } + fn parse_pipe_right(&mut self) -> Checkpoint { + self.parse_left_assoc(Self::parse_math, T!["|>"] | ()) + } + fn parse_pipe_left(&mut self) -> Checkpoint { + self.parse_right_assoc(Self::parse_pipe_right, T!["<|"] | ()) + } + /// Parse Nix code into an AST + pub fn parse_expr(&mut self) -> Checkpoint { + // Limit chosen somewhat arbitrarily + if self.depth >= 512 { + self.errors.push(ParseError::RecursionLimitExceeded); + // Consume tokens to the end of the file. Erroring without bumping might cause + // infinite looping elsewhere. + self.start_error_node(); + while self.peek().is_some() { + self.bump() + } + self.finish_error_node(); + return self.checkpoint(); + } + self.depth += 1; + let out = match self.peek() { + Some(T![let]) => { + let checkpoint = self.checkpoint(); + self.bump(); + + if self.peek() == Some(T!['{']) { + self.start_node_at(checkpoint, NODE_LEGACY_LET); + self.bump(); + self.parse_set(T!['}']); + self.finish_node(); + } else { + self.start_node_at(checkpoint, NODE_LET_IN); + self.parse_set(T![in]); + self.parse_expr(); + self.finish_node(); + } + checkpoint + } + Some(T![with]) => { + let checkpoint = self.checkpoint(); + self.start_node(NODE_WITH); + self.bump(); + self.parse_expr(); + self.expect(T![;]); + self.parse_expr(); + self.finish_node(); + checkpoint + } + Some(T![if]) => { + let checkpoint = self.checkpoint(); + self.start_node(NODE_IF_ELSE); + self.bump(); + self.parse_expr(); + self.expect(T![then]); + self.parse_expr(); + self.expect(TOKEN_ELSE); + self.parse_expr(); + self.finish_node(); + checkpoint + } + Some(T![assert]) => { + let checkpoint = self.checkpoint(); + self.start_node(NODE_ASSERT); + self.bump(); + self.parse_expr(); + self.expect(T![;]); + self.parse_expr(); + self.finish_node(); + checkpoint + } + _ => self.parse_pipe_left(), + }; + self.depth -= 1; + out + } +} + +/// Parse tokens into an AST +pub fn parse<'s, I>(iter: I) -> (GreenNode, Vec) +where + I: Iterator>, +{ + let mut parser = Parser::new(iter); + parser.builder.start_node(NixLanguage::kind_to_raw(NODE_ROOT)); + parser.parse_expr(); + parser.eat_trivia(); + if parser.peek().is_some() { + let start = parser.start_error_node(); + while parser.peek().is_some() { + parser.bump(); + } + let end = parser.finish_error_node(); + parser.errors.push(ParseError::UnexpectedExtra(TextRange::new(start, end))); + parser.eat_trivia(); + } + parser.builder.finish_node(); + (parser.builder.finish(), parser.errors) +} diff --git a/third_party/crates/rnix-0.14.0/src/tests.rs b/third_party/crates/rnix-0.14.0/src/tests.rs new file mode 100644 index 0000000..c6ea22d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/tests.rs @@ -0,0 +1,127 @@ +use std::{ffi::OsStr, fmt::Write, fs, path::PathBuf}; + +use expect_test::expect_file; +use rowan::ast::AstNode; + +use crate::{ + ast::{self, HasEntry}, + tokenize, Root, SyntaxKind, +}; + +#[test] +fn interpolation() { + let root = ast::Root::parse(include_str!("../test_data/parser/success/interpolation.nix")) + .ok() + .unwrap(); + let let_in = ast::LetIn::try_from(root.expr().unwrap()).unwrap(); + let set = ast::AttrSet::try_from(let_in.body().unwrap()).unwrap(); + let entry = set.entries().nth(1).unwrap(); + let attrpath_value = ast::AttrpathValue::try_from(entry).unwrap(); + let value = ast::Str::try_from(attrpath_value.value().unwrap()).unwrap(); + + match &*value.normalized_parts() { + &[ + ast::InterpolPart::Literal(ref s1), + ast::InterpolPart::Interpolation(_), + ast::InterpolPart::Literal(ref s2), + ast::InterpolPart::Interpolation(_), + ast::InterpolPart::Literal(ref s3) + ] + if s1 == "The set's x value is: " + && s2 == "\n\nThis line shall have no indention\n This line shall be indented by 2\n\n\n" + && s3 == "\n" => (), + parts => panic!("did not match: {:#?}", parts) +} +} + +#[test] +fn inherit() { + let root = + ast::Root::parse(include_str!("../test_data/parser/success/inherit.nix")).ok().unwrap(); + let let_in = ast::LetIn::try_from(root.expr().unwrap()).unwrap(); + let set = ast::AttrSet::try_from(let_in.body().unwrap()).unwrap(); + let inherit = set.inherits().nth(1).unwrap(); + + let from = inherit.from().unwrap().expr().unwrap(); + let ident: ast::Ident = ast::Ident::try_from(from).unwrap(); + assert_eq!(ident.syntax().text(), "set"); + let mut children = inherit.attrs(); + assert_eq!(children.next().unwrap().syntax().text(), "z"); + assert_eq!(children.next().unwrap().syntax().text(), "a"); + assert!(children.next().is_none()); +} + +#[test] +fn math() { + let root = ast::Root::parse(include_str!("../test_data/parser/success/math.nix")).ok().unwrap(); + let op1 = ast::BinOp::try_from(root.expr().unwrap()).unwrap(); + let op2 = ast::BinOp::try_from(op1.lhs().unwrap()).unwrap(); + assert_eq!(op1.operator().unwrap(), ast::BinOpKind::Add); + + let lhs = ast::Literal::try_from(op2.lhs().unwrap()).unwrap(); + assert_eq!(lhs.syntax().text(), "1"); + + let rhs = ast::BinOp::try_from(op2.rhs().unwrap()).unwrap(); + assert_eq!(rhs.operator().unwrap(), ast::BinOpKind::Mul); +} + +#[test] +fn t_macro() { + assert_eq!(T![@], SyntaxKind::TOKEN_AT); + assert!(matches!(SyntaxKind::TOKEN_L_PAREN, T!['('])); +} + +fn dir_tests(dir: &str, get_actual: F) +where + F: Fn(String) -> String, +{ + let base_path: PathBuf = [env!("CARGO_MANIFEST_DIR"), "test_data", dir].iter().collect(); + let success_path = base_path.join("success"); + let error_path = base_path.join("error"); + + let entries = success_path.read_dir().unwrap().chain(error_path.read_dir().unwrap()); + + for entry in entries { + let path = entry.unwrap().path(); + + if path.extension() != Some(OsStr::new("nix")) { + continue; + } + + println!("testing: {}", path.display()); + + let mut code = fs::read_to_string(&path).unwrap(); + if code.ends_with('\n') { + code.truncate(code.len() - 1); + } + + let actual = get_actual(code); + expect_file![path.with_extension("expect")].assert_eq(&actual); + } +} + +#[test] +fn parser_dir_tests() { + dir_tests("parser", |code| { + let parse = Root::parse(&code); + + let mut actual = String::new(); + for error in parse.errors() { + writeln!(actual, "error: {}", error).unwrap(); + } + writeln!(actual, "{:#?}", parse.syntax()).unwrap(); + + actual + }) +} + +#[test] +fn tokenizer_dir_tests() { + dir_tests("tokenizer", |code| { + let mut actual = String::new(); + for (kind, str) in tokenize(&code) { + writeln!(actual, "{:?}, \"{}\"", kind, str).unwrap(); + } + actual + }) +} diff --git a/third_party/crates/rnix-0.14.0/src/token_set.rs b/third_party/crates/rnix-0.14.0/src/token_set.rs new file mode 100644 index 0000000..1c8b02f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/token_set.rs @@ -0,0 +1,86 @@ +use std::ops; + +use crate::SyntaxKind; + +/// A bit-set of `SyntaxKind`s +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct TokenSet(u128); + +impl TokenSet { + #[allow(dead_code)] + pub(crate) const EMPTY: TokenSet = TokenSet(0); + + pub(crate) const fn new(kind: SyntaxKind) -> TokenSet { + TokenSet(mask(kind)) + } + + pub(crate) const fn from_slice(kinds: &[SyntaxKind]) -> TokenSet { + let mut res = 0u128; + let mut i = 0; + while i < kinds.len() { + res |= mask(kinds[i]); + i += 1 + } + TokenSet(res) + } + + pub(crate) const fn union(self, other: TokenSet) -> TokenSet { + TokenSet(self.0 | other.0) + } + + pub(crate) const fn contains(&self, kind: SyntaxKind) -> bool { + self.0 & mask(kind) != 0 + } +} + +const fn mask(kind: SyntaxKind) -> u128 { + 1u128 << (kind as usize) +} + +impl ops::BitOr for SyntaxKind { + type Output = TokenSet; + + fn bitor(self, rhs: Self) -> Self::Output { + TokenSet(mask(self) | mask(rhs)) + } +} + +impl ops::BitOr for TokenSet { + type Output = TokenSet; + + fn bitor(self, rhs: SyntaxKind) -> Self::Output { + self.union(TokenSet(mask(rhs))) + } +} + +impl ops::BitOr for SyntaxKind { + type Output = TokenSet; + + fn bitor(self, rhs: TokenSet) -> Self::Output { + TokenSet(mask(self)).union(rhs) + } +} + +impl ops::BitOr for TokenSet { + type Output = TokenSet; + + fn bitor(self, rhs: TokenSet) -> Self::Output { + self.union(rhs) + } +} + +impl ops::BitOr for () { + type Output = TokenSet; + + fn bitor(self, rhs: SyntaxKind) -> Self::Output { + TokenSet::new(rhs) + } +} + +impl ops::BitOr<()> for SyntaxKind { + type Output = TokenSet; + + fn bitor(self, (): ()) -> Self::Output { + TokenSet::new(self) + } +} diff --git a/third_party/crates/rnix-0.14.0/src/tokenizer.rs b/third_party/crates/rnix-0.14.0/src/tokenizer.rs new file mode 100644 index 0000000..de621f0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/src/tokenizer.rs @@ -0,0 +1,566 @@ +//! The tokenizer: turns a string into tokens, such as numbers, strings, and keywords + +use crate::SyntaxKind::{self, *}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum IdentType { + Ident, + PathRel, + PathAbs, + PathHome, + PathSearch, + Uri, +} + +fn is_valid_path_char(c: char) -> bool { + matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '/' | '_' | '.' | '+' | '-') +} + +fn is_valid_uri_char(c: char) -> bool { + match c { + '%' | '?' | ':' | '@' | '&' | '=' | '$' | ',' | '!' | '~' | '*' | '\'' => true, + _ => is_valid_path_char(c), + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Context { + StringBody { multiline: bool }, + StringEnd, + Interpol { brackets: u32 }, + InterpolStart, + Path(SyntaxKind), +} + +#[derive(Clone, Copy)] +struct State<'a> { + input: &'a str, + offset: usize, +} + +impl PartialEq for State<'_> { + fn eq(&self, other: &Self) -> bool { + std::ptr::eq(self.input, other.input) && self.offset == other.offset + } +} + +impl Eq for State<'_> {} + +pub type Token<'a> = (SyntaxKind, &'a str); + +/// Tokenize the given input +pub fn tokenize(input: &str) -> impl Iterator> + '_ { + Tokenizer::new(input) +} + +struct Tokenizer<'a> { + ctx: Vec, + state: State<'a>, +} + +impl<'a> Tokenizer<'a> { + pub fn new(input: &'a str) -> Self { + Self { ctx: Vec::new(), state: State { input, offset: 0 } } + } +} + +impl Tokenizer<'_> { + fn remaining(&self) -> &str { + &self.state.input[self.state.offset..] + } + fn peek(&self) -> Option { + self.remaining().chars().next() + } + fn next(&mut self) -> Option { + let c = self.peek(); + if let Some(c) = c { + self.state.offset += c.len_utf8(); + } + c + } + fn starts_with_bump(&mut self, s: &str) -> bool { + let starts_with = self.remaining().starts_with(s); + if starts_with { + self.state.offset += s.len(); + } + starts_with + } + fn str_since<'a>(&self, past: State<'a>) -> &'a str { + &past.input[past.offset..self.state.offset] + } + + fn push_ctx(&mut self, ctx: Context) { + self.ctx.push(ctx) + } + + fn pop_ctx(&mut self, ctx: Context) { + debug_assert!(self + .ctx + .last() + .is_some_and(|c| std::mem::discriminant(c) == std::mem::discriminant(&ctx))); + self.ctx.pop(); + } + + /// Consumes all next characters. + /// while the predicate function [f] returns true + /// + /// returns the count of consumed characters. + fn consume(&mut self, mut f: F) -> usize + where + F: FnMut(char) -> bool, + { + let len: usize = + self.remaining().chars().take_while(|&c| f(c)).map(|c| c.len_utf8()).sum::(); + self.state.offset += len; + len + } + fn next_string(&mut self, multiline: bool) -> SyntaxKind { + loop { + let start = self.state; + match self.next() { + None => { + self.pop_ctx(Context::StringBody { multiline }); + return TOKEN_ERROR; + } + Some('"') if !multiline => { + self.state = start; + self.pop_ctx(Context::StringBody { multiline: false }); + self.push_ctx(Context::StringEnd); + return TOKEN_STRING_CONTENT; + } + Some('\\') if !multiline => { + if self.next().is_none() { + return TOKEN_ERROR; + } + } + + Some('\'') if multiline => match self.peek() { + None => return TOKEN_ERROR, + Some('\'') => { + self.next(); + match self.peek() { + Some('\'') | Some('$') => { + self.next().unwrap(); + } + Some('\\') => { + self.next().unwrap(); + if self.next().is_none() { + return TOKEN_ERROR; + } + } + _ => { + self.state = start; + self.pop_ctx(Context::StringBody { multiline: true }); + self.push_ctx(Context::StringEnd); + return TOKEN_STRING_CONTENT; + } + } + } + Some(_) => (), + }, + + Some('$') => match self.peek() { + Some('$') => { + self.next().unwrap(); + } + Some('{') => { + self.state = start; + self.push_ctx(Context::InterpolStart); + return TOKEN_STRING_CONTENT; + } + _ => (), + }, + Some(_) => (), + } + } + } + + fn check_path_since(&mut self, past: State, kind: SyntaxKind) -> SyntaxKind { + self.consume(is_valid_path_char); + let path_str = self.str_since(past); + if self.remaining().starts_with("${") { + self.ctx.push(Context::InterpolStart); + } else if path_str.ends_with('/') || path_str.contains("//") { + return TOKEN_ERROR; + } else { + self.pop_ctx(Context::Path(kind)); + } + kind + } + + fn next_inner(&mut self) -> Option { + let start = self.state; + + // Handle already started multi-token + loop { + match self.ctx.last() { + Some(Context::InterpolStart) => { + self.pop_ctx(Context::InterpolStart); + self.ctx.push(Context::Interpol { brackets: 0 }); + if self.starts_with_bump("${") { + return Some(TOKEN_INTERPOL_START); + } else { + unreachable!() + } + } + Some(Context::Path(path_kind)) => { + let path_kind = *path_kind; + + // Search paths () don't support interpolation + if path_kind == TOKEN_PATH_SEARCH { + if self.peek().is_some_and(is_valid_path_char) { + return Some(self.check_path_since(start, path_kind)); + } else { + self.pop_ctx(Context::Path(path_kind)); + } + } else if self.starts_with_bump("${") { + self.ctx.push(Context::Interpol { brackets: 0 }); + return Some(TOKEN_INTERPOL_START); + } else if self.peek().is_some_and(is_valid_path_char) { + return Some(self.check_path_since(start, path_kind)); + } else { + self.pop_ctx(Context::Path(path_kind)); + } + } + Some(&Context::StringBody { multiline }) => { + let token = self.next_string(multiline); + // skip empty stuff + if self.state == start { + continue; + } + return Some(token); + } + Some(Context::StringEnd) => { + self.pop_ctx(Context::StringEnd); + let status = match self.peek() { + Some('"') => { + self.next().unwrap(); + true + } + Some('\'') => { + self.next().unwrap(); + match self.peek() { + Some('\'') => { + self.next().unwrap(); + true + } + _ => false, + } + } + _ => false, + }; + return Some(if status { TOKEN_STRING_END } else { TOKEN_ERROR }); + } + _ => (), + } + break; + } + + if self.consume(char::is_whitespace) > 0 { + return Some(TOKEN_WHITESPACE); + } + + if self.peek() == Some('#') { + self.consume(|c| c != '\n'); + return Some(TOKEN_COMMENT); + } + if self.starts_with_bump("/*") { + loop { + self.consume(|c| c != '*'); + self.next(); // consume the '*', if any + match self.peek() { + None => return Some(TOKEN_ERROR), + Some('/') => { + self.next().unwrap(); + return Some(TOKEN_COMMENT); + } + _ => (), + } + } + } + + if self.starts_with_bump("...") { + return Some(TOKEN_ELLIPSIS); + } + + // Check if it's a path + // First, simple prefix based detection for absolute ("/...") or home relative ("~/...") paths. + // For absolute paths, we need to be careful to not interfere with operators + let kind = if self.peek() == Some('/') { + // For absolute paths, we need to have a valid path character after the '/' + // AND we need to make sure it's not an operator like // + if self.remaining().starts_with("//") { + None // This could be an update operator, let the operator matcher handle it + } else if self.remaining().starts_with("/${") { + // Absolute path with interpolation, e.g. /${foo}/bar + Some(IdentType::PathAbs) + } else { + let second_char = self.remaining().chars().nth(1); + if second_char.is_some_and(|c| is_valid_path_char(c) && c != '*') { + Some(IdentType::PathAbs) + } else { + None // Not a path, might be division operator or something else + } + } + } else if self.peek() == Some('~') && self.remaining().chars().nth(1) == Some('/') { + Some(IdentType::PathHome) + } else { + // Fallback to heuristic previously used for relative, search and URI paths. + let store_path = self.peek() == Some('<'); + let skipped = self + .remaining() + .chars() + .take_while(|&c| match c { + '<' | '/' => store_path, + _ => is_valid_path_char(c), + }) + .collect::(); + + let mut lookahead = self.remaining().chars().skip(skipped.chars().count()); + + match (lookahead.next(), lookahead.next()) { + // a//b parses as Update(a, b) + (Some('/'), Some('/')) => None, + (Some('/'), Some('*')) => None, + (Some('/'), Some(c)) if !c.is_whitespace() => { + // If the first character of the yet‑to‑be‑consumed token was '/', we treat it as absolute later. + // Otherwise it's a relative path. + Some(IdentType::PathRel) + } + (Some('>'), _) => Some(IdentType::PathSearch), + (Some(':'), Some(c)) if is_valid_uri_char(c) && !skipped.contains('_') => { + Some(IdentType::Uri) + } + _ => None, + } + }; + + let c = self.next()?; + + // First, handle specific operators that might be confused with paths + if c == '/' && self.peek() == Some('/') { + // This is the update operator '//' + self.next().unwrap(); // Consume the second '/' + return Some(TOKEN_UPDATE); + } + + if c == '~' + || matches!(kind, Some(IdentType::PathAbs | IdentType::PathRel)) + || (c == '/' && self.peek().is_some_and(is_valid_path_char)) + { + return Some({ + // Determine the concrete path token kind to use + let token_kind = if c == '~' { + // we've just consumed '~', ensure '/' exists already consumed by next() + if self.next() != Some('/') { + return Some(TOKEN_ERROR); + } + TOKEN_PATH_HOME + } else { + // For abs vs rel: If the first char we consumed was '/', it's absolute. + if c == '/' { + TOKEN_PATH_ABS + } else { + TOKEN_PATH_REL + } + }; + + // Store the kind in context so subsequent segments are consistent + self.push_ctx(Context::Path(token_kind)); + self.check_path_since(start, token_kind) + }); + } + + Some(match c { + '=' if self.peek() == Some('=') => { + self.next().unwrap(); + TOKEN_EQUAL + } + '!' if self.peek() == Some('=') => { + self.next().unwrap(); + TOKEN_NOT_EQUAL + } + '!' => TOKEN_INVERT, + '{' => { + if let Some(Context::Interpol { brackets }) = self.ctx.last_mut() { + *brackets += 1; + } + TOKEN_L_BRACE + } + '}' => { + if let Some(Context::Interpol { brackets }) = self.ctx.last_mut() { + match brackets.checked_sub(1) { + Some(new) => *brackets = new, + None => { + self.pop_ctx(Context::Interpol { brackets: 0 }); + return Some(TOKEN_INTERPOL_END); + } + } + } + TOKEN_R_BRACE + } + '[' => TOKEN_L_BRACK, + ']' => TOKEN_R_BRACK, + '@' => TOKEN_AT, + ':' => TOKEN_COLON, + ',' => TOKEN_COMMA, + '.' => { + if self.peek().is_some_and(|x| x.is_ascii_digit()) { + self.consume(|c| c.is_ascii_digit()); + self.consume_scientific() + } else { + TOKEN_DOT + } + } + '=' => TOKEN_ASSIGN, + '?' => TOKEN_QUESTION, + ';' => TOKEN_SEMICOLON, + '(' => TOKEN_L_PAREN, + ')' => TOKEN_R_PAREN, + '+' if self.peek() == Some('+') => { + self.next().unwrap(); + TOKEN_CONCAT + } + '-' if self.peek() == Some('>') => { + self.next().unwrap(); + TOKEN_IMPLICATION + } + '/' if self.peek() == Some('/') => { + self.next().unwrap(); + TOKEN_UPDATE + } + '+' => TOKEN_ADD, + '-' => TOKEN_SUB, + '*' => TOKEN_MUL, + '/' => TOKEN_DIV, + '<' if self.peek() == Some('|') => { + self.next().unwrap(); + TOKEN_PIPE_LEFT + } + '<' if kind == Some(IdentType::PathSearch) => { + let content_start = self.state.offset; + self.consume(is_valid_path_char); + // Check if we consumed any content between < and > + if self.state.offset == content_start { + // Empty search path <> is not valid + TOKEN_LESS + } else if self.next() != Some('>') { + TOKEN_ERROR + } else { + TOKEN_PATH_SEARCH + } + } + '&' if self.peek() == Some('&') => { + self.next().unwrap(); + TOKEN_AND_AND + } + '|' if self.peek() == Some('>') => { + self.next().unwrap(); + TOKEN_PIPE_RIGHT + } + '|' if self.peek() == Some('|') => { + self.next().unwrap(); + TOKEN_OR_OR + } + '<' if self.peek() == Some('=') => { + self.next().unwrap(); + TOKEN_LESS_OR_EQ + } + '<' => TOKEN_LESS, + '>' if self.peek() == Some('=') => { + self.next().unwrap(); + TOKEN_MORE_OR_EQ + } + '>' => TOKEN_MORE, + '$' if self.peek() == Some('{') => { + self.next().unwrap(); + self.push_ctx(Context::Interpol { brackets: 0 }); + TOKEN_INTERPOL_START + } + 'a'..='z' | 'A'..='Z' | '_' => { + let kind = match kind { + // It's detected as store if it ends with >, but if it + // didn't start with <, that's wrong + Some(IdentType::PathSearch) | None => IdentType::Ident, + Some(kind) => kind, + }; + self.consume(|c| match c { + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '\'' => true, + c => kind == IdentType::Uri && is_valid_uri_char(c), + }); + match kind { + IdentType::Ident => match self.str_since(start) { + "assert" => TOKEN_ASSERT, + "else" => TOKEN_ELSE, + "if" => TOKEN_IF, + "in" => TOKEN_IN, + "inherit" => TOKEN_INHERIT, + "let" => TOKEN_LET, + // "or" is a contextual keyword and will be handled in the parser. + "or" => TOKEN_OR, + "rec" => TOKEN_REC, + "then" => TOKEN_THEN, + "with" => TOKEN_WITH, + _ => TOKEN_IDENT, + }, + IdentType::Uri => TOKEN_URI, + IdentType::PathAbs | IdentType::PathRel | IdentType::PathHome => { + panic!("paths are checked earlier") + } + IdentType::PathSearch => panic!("search paths are checked earlier"), + } + } + '"' => { + self.push_ctx(Context::StringBody { multiline: false }); + TOKEN_STRING_START + } + '\'' if self.peek() == Some('\'') => { + self.next().unwrap(); + self.push_ctx(Context::StringBody { multiline: true }); + TOKEN_STRING_START + } + fst @ '0'..='9' => { + // Due to nix's behavior on leading 0's we know immediately + // That a '0' followed by some other number character MUST tokenize into an INT. + // More background on this: https://github.com/nix-community/rnix-parser/issues/157 + if fst == '0' && self.peek() != Some('.') { + // In that case just consume the remaining number characters to fill the TOKEN_INTEGER + self.consume(|c| c.is_ascii_digit()); + TOKEN_INTEGER + } else { + // If we are not in that edge-case we can just continue with the regular number tokenization + self.consume(|c| c.is_ascii_digit()); + if self.peek() == Some('.') { + self.next().unwrap(); + self.consume(|c| c.is_ascii_digit()); + self.consume_scientific() + } else { + TOKEN_INTEGER + } + } + } + _ => TOKEN_ERROR, + }) + } + + fn consume_scientific(&mut self) -> SyntaxKind { + if self.peek() == Some('e') || self.peek() == Some('E') { + self.next().unwrap(); + if self.peek() == Some('-') || self.peek() == Some('+') { + self.next().unwrap(); + } + if self.consume(|c| c.is_ascii_digit()) == 0 { + return TOKEN_ERROR; + } + } + TOKEN_FLOAT + } +} + +impl<'a> Iterator for Tokenizer<'a> { + type Item = Token<'a>; + fn next(&mut self) -> Option { + let start = self.state; + self.next_inner().map(|syntax_kind| (syntax_kind, self.str_since(start))) + } +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/dollar_ident_attrpath_issue174.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/dollar_ident_attrpath_issue174.expect new file mode 100644 index 0000000..8fec177 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/dollar_ident_attrpath_issue174.expect @@ -0,0 +1,21 @@ +error: unexpected TOKEN_ERROR at 2..3, wanted any of [TOKEN_IDENT, TOKEN_OR, TOKEN_CUR_POS] +NODE_ROOT@0..12 + NODE_ATTR_SET@0..12 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..2 " " + NODE_ATTRPATH_VALUE@2..10 + NODE_ATTRPATH@2..4 + NODE_ERROR@2..3 + TOKEN_ERROR@2..3 "$" + NODE_IDENT@3..4 + TOKEN_IDENT@3..4 "a" + TOKEN_WHITESPACE@4..5 " " + TOKEN_ASSIGN@5..6 "=" + TOKEN_WHITESPACE@6..7 " " + NODE_STRING@7..9 + TOKEN_STRING_START@7..8 "\"" + TOKEN_STRING_END@8..9 "\"" + TOKEN_SEMICOLON@9..10 ";" + TOKEN_WHITESPACE@10..11 " " + TOKEN_R_BRACE@11..12 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/dollar_ident_attrpath_issue174.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/dollar_ident_attrpath_issue174.nix new file mode 100644 index 0000000..fc9f4af --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/dollar_ident_attrpath_issue174.nix @@ -0,0 +1 @@ +{ $a = ""; } \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/error.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/error.expect new file mode 100644 index 0000000..31d4150 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/error.expect @@ -0,0 +1,110 @@ +error: unexpected TOKEN_STRING_START at 10..28, wanted any of [TOKEN_ASSIGN] +error: unexpected TOKEN_STRING_START at 78..98, wanted any of [TOKEN_ASSIGN] +error: unexpected TOKEN_R_BRACE at 162..166, wanted any of [TOKEN_ASSIGN] +error: unexpected end of file, wanted any of [TOKEN_ASSIGN] +error: unexpected end of file +error: unexpected end of file, wanted any of [TOKEN_SEMICOLON] +error: unexpected end of file +error: unexpected end of file, wanted any of [TOKEN_SEMICOLON] +error: unexpected end of file +NODE_ROOT@0..166 + NODE_ATTR_SET@0..166 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..33 + NODE_ATTRPATH@4..9 + NODE_IDENT@4..9 + TOKEN_IDENT@4..9 "hello" + TOKEN_WHITESPACE@9..10 " " + NODE_ERROR@10..28 + TOKEN_STRING_START@10..11 "\"" + TOKEN_STRING_CONTENT@11..27 "Hello Ùnicödə" + TOKEN_STRING_END@27..28 "\"" + TOKEN_WHITESPACE@28..29 " " + TOKEN_ASSIGN@29..30 "=" + TOKEN_WHITESPACE@30..31 " " + NODE_LITERAL@31..32 + TOKEN_INTEGER@31..32 "1" + TOKEN_SEMICOLON@32..33 ";" + TOKEN_WHITESPACE@33..36 "\n " + NODE_ATTRPATH_VALUE@36..120 + NODE_ATTRPATH@36..40 + NODE_IDENT@36..40 + TOKEN_IDENT@36..40 "test" + TOKEN_WHITESPACE@40..41 " " + TOKEN_ASSIGN@41..42 "=" + TOKEN_WHITESPACE@42..43 " " + NODE_ATTR_SET@43..119 + TOKEN_L_BRACE@43..44 "{" + TOKEN_WHITESPACE@44..49 "\n " + NODE_ATTRPATH_VALUE@49..65 + NODE_ATTRPATH@49..54 + NODE_IDENT@49..54 + TOKEN_IDENT@49..54 "valid" + TOKEN_WHITESPACE@54..55 " " + TOKEN_ASSIGN@55..56 "=" + TOKEN_WHITESPACE@56..57 " " + NODE_STRING@57..64 + TOKEN_STRING_START@57..58 "\"" + TOKEN_STRING_CONTENT@58..63 "entry" + TOKEN_STRING_END@63..64 "\"" + TOKEN_SEMICOLON@64..65 ";" + TOKEN_WHITESPACE@65..70 "\n " + NODE_ATTRPATH_VALUE@70..115 + NODE_ATTRPATH@70..77 + NODE_IDENT@70..77 + TOKEN_IDENT@70..77 "invalid" + TOKEN_WHITESPACE@77..78 " " + NODE_ERROR@78..98 + TOKEN_STRING_START@78..79 "\"" + TOKEN_STRING_CONTENT@79..84 "entry" + TOKEN_STRING_END@84..85 "\"" + TOKEN_SEMICOLON@85..86 ";" + TOKEN_WHITESPACE@86..91 "\n " + TOKEN_IDENT@91..98 "another" + TOKEN_WHITESPACE@98..99 " " + TOKEN_ASSIGN@99..100 "=" + TOKEN_WHITESPACE@100..101 " " + NODE_STRING@101..114 + TOKEN_STRING_START@101..102 "\"" + TOKEN_STRING_CONTENT@102..113 "valid entry" + TOKEN_STRING_END@113..114 "\"" + TOKEN_SEMICOLON@114..115 ";" + TOKEN_WHITESPACE@115..118 "\n " + TOKEN_R_BRACE@118..119 "}" + TOKEN_SEMICOLON@119..120 ";" + TOKEN_WHITESPACE@120..123 "\n " + NODE_ATTRPATH_VALUE@123..166 + NODE_ATTRPATH@123..128 + NODE_IDENT@123..128 + TOKEN_IDENT@123..128 "test2" + TOKEN_WHITESPACE@128..129 " " + TOKEN_ASSIGN@129..130 "=" + TOKEN_WHITESPACE@130..131 " " + NODE_ATTR_SET@131..166 + TOKEN_L_BRACE@131..132 "{" + TOKEN_WHITESPACE@132..137 "\n " + NODE_ATTRPATH_VALUE@137..150 + NODE_ATTRPATH@137..142 + NODE_IDENT@137..142 + TOKEN_IDENT@137..142 "hello" + TOKEN_WHITESPACE@142..143 " " + TOKEN_ASSIGN@143..144 "=" + TOKEN_WHITESPACE@144..145 " " + NODE_STRING@145..149 + TOKEN_STRING_START@145..146 "\"" + TOKEN_STRING_CONTENT@146..148 "hi" + TOKEN_STRING_END@148..149 "\"" + TOKEN_SEMICOLON@149..150 ";" + TOKEN_WHITESPACE@150..155 "\n " + NODE_ATTRPATH_VALUE@155..166 + NODE_ATTRPATH@155..159 + NODE_IDENT@155..159 + TOKEN_IDENT@155..159 "aaaa" + TOKEN_WHITESPACE@159..162 "\n " + NODE_ERROR@162..166 + TOKEN_R_BRACE@162..163 "}" + TOKEN_SEMICOLON@163..164 ";" + TOKEN_WHITESPACE@164..165 "\n" + TOKEN_R_BRACE@165..166 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/error.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/error.nix new file mode 100644 index 0000000..4dd4fde --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/error.nix @@ -0,0 +1,12 @@ +{ + hello "Hello Ùnicödə" = 1; + test = { + valid = "entry"; + invalid "entry"; + another = "valid entry"; + }; + test2 = { + hello = "hi"; + aaaa + }; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/extra_comma.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/extra_comma.expect new file mode 100644 index 0000000..bd1b259 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/extra_comma.expect @@ -0,0 +1,9 @@ +error: unexpected token at 3..4 +NODE_ROOT@0..4 + NODE_ATTR_SET@0..2 + TOKEN_L_BRACE@0..1 "{" + TOKEN_R_BRACE@1..2 "}" + TOKEN_WHITESPACE@2..3 "\n" + NODE_ERROR@3..4 + TOKEN_COMMA@3..4 "," + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/extra_comma.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/extra_comma.nix new file mode 100644 index 0000000..ca18ba7 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/extra_comma.nix @@ -0,0 +1,2 @@ +{} +, \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/formals_double_bind.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/formals_double_bind.expect new file mode 100644 index 0000000..1d919c7 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/formals_double_bind.expect @@ -0,0 +1,20 @@ +error: unexpected double bind at 4..6 +NODE_ROOT@0..10 + NODE_LAMBDA@0..10 + NODE_PATTERN@0..6 + NODE_PAT_BIND@0..2 + NODE_IDENT@0..1 + TOKEN_IDENT@0..1 "f" + TOKEN_AT@1..2 "@" + TOKEN_L_BRACE@2..3 "{" + TOKEN_R_BRACE@3..4 "}" + NODE_ERROR@4..6 + TOKEN_AT@4..5 "@" + NODE_IDENT@5..6 + TOKEN_IDENT@5..6 "f" + TOKEN_COLON@6..7 ":" + TOKEN_WHITESPACE@7..8 "\n" + NODE_STRING@8..10 + TOKEN_STRING_START@8..9 "\"" + TOKEN_STRING_END@9..10 "\"" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/formals_double_bind.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/formals_double_bind.nix new file mode 100644 index 0000000..323f839 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/formals_double_bind.nix @@ -0,0 +1,2 @@ +f@{}@f: +"" \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_from_late.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_from_late.expect new file mode 100644 index 0000000..4ac8484 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_from_late.expect @@ -0,0 +1,25 @@ +error: unexpected TOKEN_L_PAREN at 12..13, wanted any of [TOKEN_IDENT, TOKEN_OR, TOKEN_CUR_POS] +error: unexpected TOKEN_R_PAREN at 14..15, wanted any of [TOKEN_IDENT, TOKEN_OR, TOKEN_CUR_POS] +NODE_ROOT@0..20 + NODE_ATTR_SET@0..20 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..2 " " + NODE_INHERIT@2..18 + TOKEN_INHERIT@2..9 "inherit" + TOKEN_WHITESPACE@9..10 " " + NODE_IDENT@10..11 + TOKEN_IDENT@10..11 "a" + TOKEN_WHITESPACE@11..12 " " + NODE_ERROR@12..13 + TOKEN_L_PAREN@12..13 "(" + NODE_IDENT@13..14 + TOKEN_IDENT@13..14 "b" + NODE_ERROR@14..15 + TOKEN_R_PAREN@14..15 ")" + TOKEN_WHITESPACE@15..16 " " + NODE_IDENT@16..17 + TOKEN_IDENT@16..17 "c" + TOKEN_SEMICOLON@17..18 ";" + TOKEN_WHITESPACE@18..19 " " + TOKEN_R_BRACE@19..20 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_from_late.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_from_late.nix new file mode 100644 index 0000000..8dba2af --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_from_late.nix @@ -0,0 +1 @@ +{ inherit a (b) c; } \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_incomplete.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_incomplete.expect new file mode 100644 index 0000000..e508add --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_incomplete.expect @@ -0,0 +1,11 @@ +error: unexpected end of file +error: unexpected end of file, wanted any of [TOKEN_SEMICOLON] +error: unexpected end of file +error: unexpected end of file +NODE_ROOT@0..13 + NODE_LET_IN@0..13 + TOKEN_LET@0..3 "let" + TOKEN_WHITESPACE@3..6 "\n " + NODE_INHERIT@6..13 + TOKEN_INHERIT@6..13 "inherit" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_incomplete.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_incomplete.nix new file mode 100644 index 0000000..bacd6b8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/inherit_incomplete.nix @@ -0,0 +1,2 @@ +let + inherit diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_bare_tilde.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_bare_tilde.expect new file mode 100644 index 0000000..3204103 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_bare_tilde.expect @@ -0,0 +1,5 @@ +error: unexpected TOKEN_ERROR at 0..1, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +NODE_ROOT@0..1 + NODE_ERROR@0..1 + TOKEN_ERROR@0..1 "~" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_bare_tilde.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_bare_tilde.nix new file mode 100644 index 0000000..4977bc6 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_bare_tilde.nix @@ -0,0 +1 @@ +~ \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_double_slash.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_double_slash.expect new file mode 100644 index 0000000..bd1c5eb --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_double_slash.expect @@ -0,0 +1,5 @@ +error: unexpected TOKEN_ERROR at 0..9, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +NODE_ROOT@0..9 + NODE_ERROR@0..9 + TOKEN_ERROR@0..9 "/foo//bar" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_double_slash.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_double_slash.nix new file mode 100644 index 0000000..483fd94 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_double_slash.nix @@ -0,0 +1 @@ +/foo//bar \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_no_separator.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_no_separator.expect new file mode 100644 index 0000000..ccf1b76 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_no_separator.expect @@ -0,0 +1,10 @@ +error: unexpected token at 1..7 +NODE_ROOT@0..7 + NODE_IDENT@0..1 + TOKEN_IDENT@0..1 "a" + NODE_ERROR@1..7 + TOKEN_INTERPOL_START@1..3 "${" + TOKEN_IDENT@3..4 "b" + TOKEN_INTERPOL_END@4..5 "}" + TOKEN_PATH_ABS@5..7 "/c" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_no_separator.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_no_separator.nix new file mode 100644 index 0000000..49397e9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_no_separator.nix @@ -0,0 +1 @@ +a${b}/c diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_trailing_slash.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_trailing_slash.expect new file mode 100644 index 0000000..72e47ec --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_trailing_slash.expect @@ -0,0 +1,12 @@ +error: unexpected token at 8..9 +NODE_ROOT@0..9 + NODE_PATH_REL@0..8 + TOKEN_PATH_REL@0..2 "./" + NODE_INTERPOL@2..8 + TOKEN_INTERPOL_START@2..4 "${" + NODE_IDENT@4..7 + TOKEN_IDENT@4..7 "foo" + TOKEN_INTERPOL_END@7..8 "}" + NODE_ERROR@8..9 + TOKEN_ERROR@8..9 "/" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_trailing_slash.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_trailing_slash.nix new file mode 100644 index 0000000..968abc8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_interp_trailing_slash.nix @@ -0,0 +1 @@ +./${foo}/ diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_multiple_errors.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_multiple_errors.expect new file mode 100644 index 0000000..02f3633 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_multiple_errors.expect @@ -0,0 +1,59 @@ +error: unexpected TOKEN_ERROR at 57..66, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +error: unexpected TOKEN_ERROR at 84..93, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +error: unexpected TOKEN_ERROR at 108..110, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +error: unexpected TOKEN_ERROR at 128..133, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +NODE_ROOT@0..141 + NODE_ATTR_SET@0..141 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + TOKEN_COMMENT@4..38 "# Multiple path error ..." + TOKEN_WHITESPACE@38..41 "\n " + NODE_ATTRPATH_VALUE@41..67 + NODE_ATTRPATH@41..54 + NODE_IDENT@41..54 + TOKEN_IDENT@41..54 "trailingSlash" + TOKEN_WHITESPACE@54..55 " " + TOKEN_ASSIGN@55..56 "=" + TOKEN_WHITESPACE@56..57 " " + NODE_ERROR@57..66 + TOKEN_ERROR@57..66 "/foo/bar/" + TOKEN_SEMICOLON@66..67 ";" + TOKEN_WHITESPACE@67..70 "\n " + NODE_ATTRPATH_VALUE@70..94 + NODE_ATTRPATH@70..81 + NODE_IDENT@70..81 + TOKEN_IDENT@70..81 "doubleSlash" + TOKEN_WHITESPACE@81..82 " " + TOKEN_ASSIGN@82..83 "=" + TOKEN_WHITESPACE@83..84 " " + NODE_ERROR@84..93 + TOKEN_ERROR@84..93 "/foo//bar" + TOKEN_SEMICOLON@93..94 ";" + TOKEN_WHITESPACE@94..97 "\n " + NODE_ATTRPATH_VALUE@97..111 + NODE_ATTRPATH@97..105 + NODE_IDENT@97..105 + TOKEN_IDENT@97..105 "bareHome" + TOKEN_WHITESPACE@105..106 " " + TOKEN_ASSIGN@106..107 "=" + TOKEN_WHITESPACE@107..108 " " + NODE_ERROR@108..110 + TOKEN_ERROR@108..110 "~/" + TOKEN_SEMICOLON@110..111 ";" + TOKEN_WHITESPACE@111..114 "\n " + NODE_ATTRPATH_VALUE@114..139 + NODE_ATTRPATH@114..125 + NODE_IDENT@114..125 + TOKEN_IDENT@114..125 "tildeMiddle" + TOKEN_WHITESPACE@125..126 " " + TOKEN_ASSIGN@126..127 "=" + TOKEN_WHITESPACE@127..128 " " + NODE_APPLY@128..138 + NODE_ERROR@128..133 + TOKEN_ERROR@128..133 "/foo/" + NODE_PATH_HOME@133..138 + TOKEN_PATH_HOME@133..138 "~/bar" + TOKEN_SEMICOLON@138..139 ";" + TOKEN_WHITESPACE@139..140 "\n" + TOKEN_R_BRACE@140..141 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_multiple_errors.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_multiple_errors.nix new file mode 100644 index 0000000..69e7d5f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_multiple_errors.nix @@ -0,0 +1,7 @@ +{ + # Multiple path errors in one file + trailingSlash = /foo/bar/; + doubleSlash = /foo//bar; + bareHome = ~/; + tildeMiddle = /foo/~/bar; +} \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_store_interp.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_store_interp.expect new file mode 100644 index 0000000..142c36f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_store_interp.expect @@ -0,0 +1,17 @@ +error: unexpected TOKEN_LESS at 0..1, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +error: unexpected end of file +NODE_ROOT@0..20 + NODE_BIN_OP@0..20 + NODE_APPLY@0..19 + NODE_ERROR@0..1 + TOKEN_LESS@0..1 "<" + NODE_PATH_REL@1..19 + TOKEN_PATH_REL@1..9 "nixpkgs/" + NODE_INTERPOL@9..15 + TOKEN_INTERPOL_START@9..11 "${" + NODE_IDENT@11..14 + TOKEN_IDENT@11..14 "foo" + TOKEN_INTERPOL_END@14..15 "}" + TOKEN_PATH_REL@15..19 "/bar" + TOKEN_MORE@19..20 ">" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_store_interp.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_store_interp.nix new file mode 100644 index 0000000..cbc1bd9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_store_interp.nix @@ -0,0 +1 @@ + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde.expect new file mode 100644 index 0000000..9dfb5c6 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde.expect @@ -0,0 +1,5 @@ +error: unexpected TOKEN_ERROR at 0..2, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +NODE_ROOT@0..2 + NODE_ERROR@0..2 + TOKEN_ERROR@0..2 "~p" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde.nix new file mode 100644 index 0000000..9199bb7 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde.nix @@ -0,0 +1 @@ +~p \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde_slash.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde_slash.expect new file mode 100644 index 0000000..cdeecb3 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde_slash.expect @@ -0,0 +1,5 @@ +error: unexpected TOKEN_ERROR at 0..2, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +NODE_ROOT@0..2 + NODE_ERROR@0..2 + TOKEN_ERROR@0..2 "~/" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde_slash.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde_slash.nix new file mode 100644 index 0000000..81ca0f5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_tilde_slash.nix @@ -0,0 +1 @@ +~/ diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_trailing_slash.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_trailing_slash.expect new file mode 100644 index 0000000..bdf75f5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_trailing_slash.expect @@ -0,0 +1,5 @@ +error: unexpected TOKEN_ERROR at 0..3, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +NODE_ROOT@0..3 + NODE_ERROR@0..3 + TOKEN_ERROR@0..3 "/a/" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/path_trailing_slash.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_trailing_slash.nix new file mode 100644 index 0000000..6637752 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/path_trailing_slash.nix @@ -0,0 +1 @@ +/a/ diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/select_both_errors.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/select_both_errors.expect new file mode 100644 index 0000000..b1ab860 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/select_both_errors.expect @@ -0,0 +1,9 @@ +error: unexpected TOKEN_R_BRACK at 0..1, wanted any of [TOKEN_L_PAREN, TOKEN_REC, TOKEN_L_BRACE, TOKEN_L_BRACK, TOKEN_STRING_START, TOKEN_IDENT] +error: unexpected end of file, wanted any of [TOKEN_IDENT, TOKEN_OR, TOKEN_CUR_POS] +NODE_ROOT@0..2 + NODE_SELECT@0..2 + NODE_ERROR@0..1 + TOKEN_R_BRACK@0..1 "]" + TOKEN_DOT@1..2 "." + NODE_ATTRPATH@2..2 + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/select_both_errors.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/select_both_errors.nix new file mode 100644 index 0000000..5bd6850 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/select_both_errors.nix @@ -0,0 +1 @@ +]. diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root.expect new file mode 100644 index 0000000..58afe51 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root.expect @@ -0,0 +1,23 @@ +error: unexpected end of file +error: unexpected end of file, wanted any of [TOKEN_SEMICOLON] +error: unexpected end of file +NODE_ROOT@0..50 + NODE_ATTR_SET@0..48 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..48 + NODE_ATTRPATH@4..11 + NODE_IDENT@4..11 + TOKEN_IDENT@4..11 "traceIf" + TOKEN_WHITESPACE@11..12 " " + TOKEN_ASSIGN@12..13 "=" + TOKEN_WHITESPACE@13..18 "\n " + TOKEN_COMMENT@18..38 "# predicate to check" + TOKEN_WHITESPACE@38..43 "\n " + NODE_LAMBDA@43..48 + NODE_IDENT_PARAM@43..47 + NODE_IDENT@43..47 + TOKEN_IDENT@43..47 "pred" + TOKEN_COLON@47..48 ":" + TOKEN_WHITESPACE@48..50 "\n\n" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root.nix new file mode 100644 index 0000000..90703c3 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root.nix @@ -0,0 +1,6 @@ +{ + traceIf = + # predicate to check + pred: + + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root2.expect b/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root2.expect new file mode 100644 index 0000000..fea8464 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root2.expect @@ -0,0 +1,10 @@ +error: unexpected token at 3..4 +NODE_ROOT@0..5 + NODE_ATTR_SET@0..2 + TOKEN_L_BRACE@0..1 "{" + TOKEN_R_BRACE@1..2 "}" + TOKEN_WHITESPACE@2..3 " " + NODE_ERROR@3..4 + TOKEN_ASSIGN@3..4 "=" + TOKEN_WHITESPACE@4..5 "\n" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root2.nix b/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root2.nix new file mode 100644 index 0000000..653b245 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/error/ws_belongs_to_root2.nix @@ -0,0 +1,2 @@ +{} = + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/apply.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/apply.expect new file mode 100644 index 0000000..332c29a --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/apply.expect @@ -0,0 +1,18 @@ +NODE_ROOT@0..9 + NODE_BIN_OP@0..9 + NODE_APPLY@0..5 + NODE_APPLY@0..3 + NODE_IDENT@0..1 + TOKEN_IDENT@0..1 "a" + TOKEN_WHITESPACE@1..2 " " + NODE_LITERAL@2..3 + TOKEN_INTEGER@2..3 "1" + TOKEN_WHITESPACE@3..4 " " + NODE_LITERAL@4..5 + TOKEN_INTEGER@4..5 "2" + TOKEN_WHITESPACE@5..6 " " + TOKEN_ADD@6..7 "+" + TOKEN_WHITESPACE@7..8 " " + NODE_LITERAL@8..9 + TOKEN_INTEGER@8..9 "3" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/apply.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/apply.nix new file mode 100644 index 0000000..b471ef8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/apply.nix @@ -0,0 +1 @@ +a 1 2 + 3 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/assert.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/assert.expect new file mode 100644 index 0000000..095a1c2 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/assert.expect @@ -0,0 +1,16 @@ +NODE_ROOT@0..18 + NODE_ASSERT@0..18 + TOKEN_ASSERT@0..6 "assert" + TOKEN_WHITESPACE@6..7 " " + NODE_BIN_OP@7..11 + NODE_IDENT@7..8 + TOKEN_IDENT@7..8 "a" + TOKEN_EQUAL@8..10 "==" + NODE_IDENT@10..11 + TOKEN_IDENT@10..11 "b" + TOKEN_SEMICOLON@11..12 ";" + NODE_STRING@12..18 + TOKEN_STRING_START@12..13 "\"" + TOKEN_STRING_CONTENT@13..17 "a==b" + TOKEN_STRING_END@17..18 "\"" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/assert.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/assert.nix new file mode 100644 index 0000000..95778ae --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/assert.nix @@ -0,0 +1 @@ +assert a==b;"a==b" diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrpath_ident.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrpath_ident.expect new file mode 100644 index 0000000..7d38eb4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrpath_ident.expect @@ -0,0 +1,19 @@ +NODE_ROOT@0..10 + NODE_ATTR_SET@0..10 + TOKEN_L_BRACE@0..1 "{" + NODE_ATTRPATH_VALUE@1..9 + NODE_ATTRPATH@1..6 + NODE_IDENT@1..2 + TOKEN_IDENT@1..2 "a" + TOKEN_DOT@2..3 "." + NODE_IDENT@3..4 + TOKEN_IDENT@3..4 "b" + TOKEN_DOT@4..5 "." + NODE_IDENT@5..6 + TOKEN_IDENT@5..6 "c" + TOKEN_ASSIGN@6..7 "=" + NODE_LITERAL@7..8 + TOKEN_INTEGER@7..8 "1" + TOKEN_SEMICOLON@8..9 ";" + TOKEN_R_BRACE@9..10 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrpath_ident.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrpath_ident.nix new file mode 100644 index 0000000..2cc87e8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrpath_ident.nix @@ -0,0 +1 @@ +{a.b.c=1;} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset.expect new file mode 100644 index 0000000..8ab7614 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset.expect @@ -0,0 +1,28 @@ +NODE_ROOT@0..49 + NODE_ATTR_SET@0..49 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..25 + NODE_ATTRPATH@4..19 + NODE_IDENT@4..19 + TOKEN_IDENT@4..19 "meaning_of_life" + TOKEN_WHITESPACE@19..20 " " + TOKEN_ASSIGN@20..21 "=" + TOKEN_WHITESPACE@21..22 " " + NODE_LITERAL@22..24 + TOKEN_INTEGER@22..24 "42" + TOKEN_SEMICOLON@24..25 ";" + TOKEN_WHITESPACE@25..28 "\n " + NODE_ATTRPATH_VALUE@28..47 + NODE_ATTRPATH@28..38 + NODE_IDENT@28..38 + TOKEN_IDENT@28..38 "H4X0RNUM83" + TOKEN_WHITESPACE@38..39 " " + TOKEN_ASSIGN@39..40 "=" + TOKEN_WHITESPACE@40..41 " " + NODE_LITERAL@41..46 + TOKEN_FLOAT@41..46 "1.337" + TOKEN_SEMICOLON@46..47 ";" + TOKEN_WHITESPACE@47..48 "\n" + TOKEN_R_BRACE@48..49 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset.nix new file mode 100644 index 0000000..988941e --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset.nix @@ -0,0 +1,4 @@ +{ + meaning_of_life = 42; + H4X0RNUM83 = 1.337; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_dynamic.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_dynamic.expect new file mode 100644 index 0000000..b4f2cce --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_dynamic.expect @@ -0,0 +1,43 @@ +NODE_ROOT@0..33 + NODE_ATTR_SET@0..33 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..12 + NODE_ATTRPATH@4..7 + NODE_IDENT@4..5 + TOKEN_IDENT@4..5 "a" + TOKEN_DOT@5..6 "." + NODE_IDENT@6..7 + TOKEN_IDENT@6..7 "b" + TOKEN_WHITESPACE@7..8 " " + TOKEN_ASSIGN@8..9 "=" + TOKEN_WHITESPACE@9..10 " " + NODE_LITERAL@10..11 + TOKEN_INTEGER@10..11 "2" + TOKEN_SEMICOLON@11..12 ";" + TOKEN_WHITESPACE@12..15 "\n " + NODE_ATTRPATH_VALUE@15..31 + NODE_ATTRPATH@15..26 + NODE_STRING@15..21 + TOKEN_STRING_START@15..16 "\"" + NODE_INTERPOL@16..20 + TOKEN_INTERPOL_START@16..18 "${" + NODE_IDENT@18..19 + TOKEN_IDENT@18..19 "c" + TOKEN_INTERPOL_END@19..20 "}" + TOKEN_STRING_END@20..21 "\"" + TOKEN_DOT@21..22 "." + NODE_DYNAMIC@22..26 + TOKEN_INTERPOL_START@22..24 "${" + NODE_IDENT@24..25 + TOKEN_IDENT@24..25 "d" + TOKEN_INTERPOL_END@25..26 "}" + TOKEN_WHITESPACE@26..27 " " + TOKEN_ASSIGN@27..28 "=" + TOKEN_WHITESPACE@28..29 " " + NODE_LITERAL@29..30 + TOKEN_INTEGER@29..30 "3" + TOKEN_SEMICOLON@30..31 ";" + TOKEN_WHITESPACE@31..32 "\n" + TOKEN_R_BRACE@32..33 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_dynamic.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_dynamic.nix new file mode 100644 index 0000000..30dccb6 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_dynamic.nix @@ -0,0 +1,4 @@ +{ + a.b = 2; + "${c}".${d} = 3; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_empty.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_empty.expect new file mode 100644 index 0000000..44ed836 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_empty.expect @@ -0,0 +1,5 @@ +NODE_ROOT@0..2 + NODE_ATTR_SET@0..2 + TOKEN_L_BRACE@0..1 "{" + TOKEN_R_BRACE@1..2 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_empty.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_empty.nix new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_empty.nix @@ -0,0 +1 @@ +{} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_rec.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_rec.expect new file mode 100644 index 0000000..5737025 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_rec.expect @@ -0,0 +1,14 @@ +NODE_ROOT@0..12 + NODE_ATTR_SET@0..12 + TOKEN_REC@0..3 "rec" + TOKEN_L_BRACE@3..4 "{" + NODE_ATTRPATH_VALUE@4..11 + NODE_ATTRPATH@4..8 + NODE_IDENT@4..8 + TOKEN_IDENT@4..8 "test" + TOKEN_ASSIGN@8..9 "=" + NODE_LITERAL@9..10 + TOKEN_INTEGER@9..10 "1" + TOKEN_SEMICOLON@10..11 ";" + TOKEN_R_BRACE@11..12 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_rec.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_rec.nix new file mode 100644 index 0000000..24043be --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/attrset_rec.nix @@ -0,0 +1 @@ +rec{test=1;} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_arith_ops.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_arith_ops.expect new file mode 100644 index 0000000..c4db318 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_arith_ops.expect @@ -0,0 +1,32 @@ +NODE_ROOT@0..20 + NODE_BIN_OP@0..20 + NODE_BIN_OP@0..3 + NODE_LITERAL@0..1 + TOKEN_INTEGER@0..1 "1" + TOKEN_LESS@1..2 "<" + NODE_LITERAL@2..3 + TOKEN_INTEGER@2..3 "2" + TOKEN_OR_OR@3..5 "||" + NODE_BIN_OP@5..20 + NODE_BIN_OP@5..14 + NODE_BIN_OP@5..9 + NODE_LITERAL@5..6 + TOKEN_INTEGER@5..6 "2" + TOKEN_LESS_OR_EQ@6..8 "<=" + NODE_LITERAL@8..9 + TOKEN_INTEGER@8..9 "2" + TOKEN_AND_AND@9..11 "&&" + NODE_BIN_OP@11..14 + NODE_LITERAL@11..12 + TOKEN_INTEGER@11..12 "2" + TOKEN_MORE@12..13 ">" + NODE_LITERAL@13..14 + TOKEN_INTEGER@13..14 "1" + TOKEN_AND_AND@14..16 "&&" + NODE_BIN_OP@16..20 + NODE_LITERAL@16..17 + TOKEN_INTEGER@16..17 "2" + TOKEN_MORE_OR_EQ@17..19 ">=" + NODE_LITERAL@19..20 + TOKEN_INTEGER@19..20 "2" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_arith_ops.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_arith_ops.nix new file mode 100644 index 0000000..8bf6ab0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_arith_ops.nix @@ -0,0 +1 @@ +1<2||2<=2&&2>1&&2>=2 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops.expect new file mode 100644 index 0000000..a36fd26 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops.expect @@ -0,0 +1,23 @@ +NODE_ROOT@0..33 + NODE_BIN_OP@0..33 + NODE_IDENT@0..5 + TOKEN_IDENT@0..5 "false" + TOKEN_WHITESPACE@5..6 " " + TOKEN_IMPLICATION@6..8 "->" + NODE_BIN_OP@8..33 + NODE_BIN_OP@8..27 + NODE_UNARY_OP@8..14 + TOKEN_INVERT@8..9 "!" + NODE_IDENT@9..14 + TOKEN_IDENT@9..14 "false" + TOKEN_AND_AND@14..16 "&&" + NODE_BIN_OP@16..27 + NODE_IDENT@16..21 + TOKEN_IDENT@16..21 "false" + TOKEN_EQUAL@21..23 "==" + NODE_IDENT@23..27 + TOKEN_IDENT@23..27 "true" + TOKEN_OR_OR@27..29 "||" + NODE_IDENT@29..33 + TOKEN_IDENT@29..33 "true" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops.nix new file mode 100644 index 0000000..748c3e3 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops.nix @@ -0,0 +1 @@ +false ->!false&&false==true||true diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops_eq.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops_eq.expect new file mode 100644 index 0000000..0103a74 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops_eq.expect @@ -0,0 +1,16 @@ +NODE_ROOT@0..10 + NODE_BIN_OP@0..10 + NODE_BIN_OP@0..4 + NODE_LITERAL@0..1 + TOKEN_INTEGER@0..1 "1" + TOKEN_EQUAL@1..3 "==" + NODE_LITERAL@3..4 + TOKEN_INTEGER@3..4 "1" + TOKEN_AND_AND@4..6 "&&" + NODE_BIN_OP@6..10 + NODE_LITERAL@6..7 + TOKEN_INTEGER@6..7 "2" + TOKEN_NOT_EQUAL@7..9 "!=" + NODE_LITERAL@9..10 + TOKEN_INTEGER@9..10 "3" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops_eq.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops_eq.nix new file mode 100644 index 0000000..e87de3d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/bool_ops_eq.nix @@ -0,0 +1 @@ +1==1&&2!=3 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-arg.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-arg.expect new file mode 100644 index 0000000..3f1d4af --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-arg.expect @@ -0,0 +1,30 @@ +NODE_ROOT@0..44 + NODE_STRING@0..44 + TOKEN_STRING_START@0..1 "\"" + NODE_INTERPOL@1..17 + TOKEN_INTERPOL_START@1..3 "${" + NODE_SELECT@3..16 + NODE_CUR_POS@3..11 + TOKEN_CUR_POS@3..11 "__curPos" + TOKEN_DOT@11..12 "." + NODE_ATTRPATH@12..16 + NODE_IDENT@12..16 + TOKEN_IDENT@12..16 "file" + TOKEN_INTERPOL_END@16..17 "}" + TOKEN_STRING_CONTENT@17..18 ":" + NODE_INTERPOL@18..43 + TOKEN_INTERPOL_START@18..20 "${" + NODE_APPLY@20..42 + NODE_IDENT@20..28 + TOKEN_IDENT@20..28 "toString" + TOKEN_WHITESPACE@28..29 " " + NODE_SELECT@29..42 + NODE_CUR_POS@29..37 + TOKEN_CUR_POS@29..37 "__curPos" + TOKEN_DOT@37..38 "." + NODE_ATTRPATH@38..42 + NODE_IDENT@38..42 + TOKEN_IDENT@38..42 "line" + TOKEN_INTERPOL_END@42..43 "}" + TOKEN_STRING_END@43..44 "\"" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-arg.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-arg.nix new file mode 100644 index 0000000..60f0254 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-arg.nix @@ -0,0 +1 @@ +"${__curPos.file}:${toString __curPos.line}" diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-ident.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-ident.expect new file mode 100644 index 0000000..3c3405f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-ident.expect @@ -0,0 +1,22 @@ +NODE_ROOT@0..26 + NODE_SELECT@0..26 + NODE_ATTR_SET@0..17 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..2 " " + NODE_ATTRPATH_VALUE@2..15 + NODE_ATTRPATH@2..10 + NODE_IDENT@2..10 + TOKEN_IDENT@2..10 "__curPos" + TOKEN_WHITESPACE@10..11 " " + TOKEN_ASSIGN@11..12 "=" + TOKEN_WHITESPACE@12..13 " " + NODE_LITERAL@13..14 + TOKEN_INTEGER@13..14 "1" + TOKEN_SEMICOLON@14..15 ";" + TOKEN_WHITESPACE@15..16 " " + TOKEN_R_BRACE@16..17 "}" + TOKEN_DOT@17..18 "." + NODE_ATTRPATH@18..26 + NODE_IDENT@18..26 + TOKEN_IDENT@18..26 "__curPos" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-ident.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-ident.nix new file mode 100644 index 0000000..ad3f9db --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-as-ident.nix @@ -0,0 +1 @@ +{ __curPos = 1; }.__curPos diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-lambda.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-lambda.expect new file mode 100644 index 0000000..31258f1 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-lambda.expect @@ -0,0 +1,10 @@ +NODE_ROOT@0..18 + NODE_LAMBDA@0..18 + NODE_IDENT_PARAM@0..8 + NODE_IDENT@0..8 + TOKEN_IDENT@0..8 "__curPos" + TOKEN_COLON@8..9 ":" + TOKEN_WHITESPACE@9..10 " " + NODE_CUR_POS@10..18 + TOKEN_CUR_POS@10..18 "__curPos" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-lambda.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-lambda.nix new file mode 100644 index 0000000..ec7ac33 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-lambda.nix @@ -0,0 +1 @@ +__curPos: __curPos diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-no-shadow.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-no-shadow.expect new file mode 100644 index 0000000..d4a2e40 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-no-shadow.expect @@ -0,0 +1,22 @@ +NODE_ROOT@0..32 + NODE_LET_IN@0..32 + TOKEN_LET@0..3 "let" + TOKEN_WHITESPACE@3..4 " " + NODE_ATTRPATH_VALUE@4..20 + NODE_ATTRPATH@4..12 + NODE_IDENT@4..12 + TOKEN_IDENT@4..12 "__curPos" + TOKEN_WHITESPACE@12..13 " " + TOKEN_ASSIGN@13..14 "=" + TOKEN_WHITESPACE@14..15 " " + NODE_STRING@15..19 + TOKEN_STRING_START@15..16 "\"" + TOKEN_STRING_CONTENT@16..18 "no" + TOKEN_STRING_END@18..19 "\"" + TOKEN_SEMICOLON@19..20 ";" + TOKEN_WHITESPACE@20..21 " " + TOKEN_IN@21..23 "in" + TOKEN_WHITESPACE@23..24 " " + NODE_CUR_POS@24..32 + TOKEN_CUR_POS@24..32 "__curPos" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-no-shadow.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-no-shadow.nix new file mode 100644 index 0000000..cd626ea --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-no-shadow.nix @@ -0,0 +1 @@ +let __curPos = "no"; in __curPos diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-bind.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-bind.expect new file mode 100644 index 0000000..c98f520 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-bind.expect @@ -0,0 +1,17 @@ +NODE_ROOT@0..24 + NODE_LAMBDA@0..24 + NODE_PATTERN@0..14 + NODE_PAT_BIND@0..10 + NODE_IDENT@0..8 + TOKEN_IDENT@0..8 "__curPos" + TOKEN_WHITESPACE@8..9 " " + TOKEN_AT@9..10 "@" + TOKEN_WHITESPACE@10..11 " " + TOKEN_L_BRACE@11..12 "{" + TOKEN_WHITESPACE@12..13 " " + TOKEN_R_BRACE@13..14 "}" + TOKEN_COLON@14..15 ":" + TOKEN_WHITESPACE@15..16 " " + NODE_CUR_POS@16..24 + TOKEN_CUR_POS@16..24 "__curPos" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-bind.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-bind.nix new file mode 100644 index 0000000..18589a0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-bind.nix @@ -0,0 +1 @@ +__curPos @ { }: __curPos diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field-default.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field-default.expect new file mode 100644 index 0000000..0c95eea --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field-default.expect @@ -0,0 +1,20 @@ +NODE_ROOT@0..26 + NODE_LAMBDA@0..26 + NODE_PATTERN@0..16 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..2 " " + NODE_PAT_ENTRY@2..14 + NODE_IDENT@2..10 + TOKEN_IDENT@2..10 "__curPos" + TOKEN_WHITESPACE@10..11 " " + TOKEN_QUESTION@11..12 "?" + TOKEN_WHITESPACE@12..13 " " + NODE_LITERAL@13..14 + TOKEN_INTEGER@13..14 "1" + TOKEN_WHITESPACE@14..15 " " + TOKEN_R_BRACE@15..16 "}" + TOKEN_COLON@16..17 ":" + TOKEN_WHITESPACE@17..18 " " + NODE_CUR_POS@18..26 + TOKEN_CUR_POS@18..26 "__curPos" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field-default.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field-default.nix new file mode 100644 index 0000000..0004f1b --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field-default.nix @@ -0,0 +1 @@ +{ __curPos ? 1 }: __curPos diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field.expect new file mode 100644 index 0000000..e66674a --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field.expect @@ -0,0 +1,18 @@ +NODE_ROOT@0..27 + NODE_LAMBDA@0..27 + NODE_PATTERN@0..17 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..2 " " + NODE_PAT_ENTRY@2..10 + NODE_IDENT@2..10 + TOKEN_IDENT@2..10 "__curPos" + TOKEN_COMMA@10..11 "," + TOKEN_WHITESPACE@11..12 " " + TOKEN_ELLIPSIS@12..15 "..." + TOKEN_WHITESPACE@15..16 " " + TOKEN_R_BRACE@16..17 "}" + TOKEN_COLON@17..18 ":" + TOKEN_WHITESPACE@18..19 " " + NODE_CUR_POS@19..27 + TOKEN_CUR_POS@19..27 "__curPos" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field.nix new file mode 100644 index 0000000..a35fb7b --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos-pattern-field.nix @@ -0,0 +1 @@ +{ __curPos, ... }: __curPos diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos.expect new file mode 100644 index 0000000..7dfe1ca --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos.expect @@ -0,0 +1,4 @@ +NODE_ROOT@0..8 + NODE_CUR_POS@0..8 + TOKEN_CUR_POS@0..8 "__curPos" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos.nix new file mode 100644 index 0000000..fff8bd3 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/cur_pos.nix @@ -0,0 +1 @@ +__curPos diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/docs.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/docs.expect new file mode 100644 index 0000000..4a72db0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/docs.expect @@ -0,0 +1,85 @@ +NODE_ROOT@0..306 + TOKEN_COMMENT@0..35 "# Test used by exampl ..." + TOKEN_WHITESPACE@35..36 "\n" + NODE_ATTR_SET@36..306 + TOKEN_REC@36..39 "rec" + TOKEN_WHITESPACE@39..40 " " + TOKEN_L_BRACE@40..41 "{" + TOKEN_WHITESPACE@41..44 "\n " + TOKEN_COMMENT@44..60 "# Usage: add x y" + TOKEN_WHITESPACE@60..63 "\n " + TOKEN_COMMENT@63..122 "# Adds the integers x ..." + TOKEN_WHITESPACE@122..125 "\n " + NODE_ATTRPATH_VALUE@125..196 + NODE_ATTRPATH@125..128 + NODE_IDENT@125..128 + TOKEN_IDENT@125..128 "add" + TOKEN_WHITESPACE@128..129 " " + TOKEN_ASSIGN@129..130 "=" + TOKEN_WHITESPACE@130..135 "\n " + TOKEN_COMMENT@135..150 "# First integer" + TOKEN_WHITESPACE@150..155 "\n " + NODE_LAMBDA@155..195 + NODE_IDENT_PARAM@155..156 + NODE_IDENT@155..156 + TOKEN_IDENT@155..156 "x" + TOKEN_COLON@156..157 ":" + TOKEN_WHITESPACE@157..162 "\n " + TOKEN_COMMENT@162..178 "# Second integer" + TOKEN_WHITESPACE@178..183 "\n " + NODE_LAMBDA@183..195 + NODE_IDENT_PARAM@183..184 + NODE_IDENT@183..184 + TOKEN_IDENT@183..184 "y" + TOKEN_COLON@184..185 ":" + TOKEN_WHITESPACE@185..190 "\n " + NODE_BIN_OP@190..195 + NODE_IDENT@190..191 + TOKEN_IDENT@190..191 "x" + TOKEN_WHITESPACE@191..192 " " + TOKEN_ADD@192..193 "+" + TOKEN_WHITESPACE@193..194 " " + NODE_IDENT@194..195 + TOKEN_IDENT@194..195 "y" + TOKEN_SEMICOLON@195..196 ";" + TOKEN_WHITESPACE@196..199 "\n " + TOKEN_COMMENT@199..216 "# Usage: sum nums" + TOKEN_WHITESPACE@216..219 "\n " + TOKEN_COMMENT@219..262 "# Returns the sum of ..." + TOKEN_WHITESPACE@262..265 "\n " + NODE_ATTRPATH_VALUE@265..304 + NODE_ATTRPATH@265..268 + NODE_IDENT@265..268 + TOKEN_IDENT@265..268 "sum" + TOKEN_WHITESPACE@268..269 " " + TOKEN_ASSIGN@269..270 "=" + TOKEN_WHITESPACE@270..271 " " + NODE_LAMBDA@271..303 + NODE_IDENT_PARAM@271..275 + NODE_IDENT@271..275 + TOKEN_IDENT@271..275 "nums" + TOKEN_COLON@275..276 ":" + TOKEN_WHITESPACE@276..277 " " + NODE_APPLY@277..303 + NODE_APPLY@277..298 + NODE_APPLY@277..296 + NODE_SELECT@277..292 + NODE_IDENT@277..285 + TOKEN_IDENT@277..285 "builtins" + TOKEN_DOT@285..286 "." + NODE_ATTRPATH@286..292 + NODE_IDENT@286..292 + TOKEN_IDENT@286..292 "foldl'" + TOKEN_WHITESPACE@292..293 " " + NODE_IDENT@293..296 + TOKEN_IDENT@293..296 "add" + TOKEN_WHITESPACE@296..297 " " + NODE_LITERAL@297..298 + TOKEN_INTEGER@297..298 "0" + TOKEN_WHITESPACE@298..299 " " + NODE_IDENT@299..303 + TOKEN_IDENT@299..303 "nums" + TOKEN_SEMICOLON@303..304 ";" + TOKEN_WHITESPACE@304..305 "\n" + TOKEN_R_BRACE@305..306 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/docs.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/docs.nix new file mode 100644 index 0000000..f33361c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/docs.nix @@ -0,0 +1,14 @@ +# Test used by examples/list-fns.rs +rec { + # Usage: add x y + # Adds the integers x and y together and returns the result + add = + # First integer + x: + # Second integer + y: + x + y; + # Usage: sum nums + # Returns the sum of the integer array nums + sum = nums: builtins.foldl' add 0 nums; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/has_attr_prec.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/has_attr_prec.expect new file mode 100644 index 0000000..dae2277 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/has_attr_prec.expect @@ -0,0 +1,15 @@ +NODE_ROOT@0..11 + NODE_BIN_OP@0..11 + NODE_HAS_ATTR@0..5 + NODE_IDENT@0..1 + TOKEN_IDENT@0..1 "a" + TOKEN_QUESTION@1..2 "?" + NODE_ATTRPATH@2..5 + NODE_STRING@2..5 + TOKEN_STRING_START@2..3 "\"" + TOKEN_STRING_CONTENT@3..4 "b" + TOKEN_STRING_END@4..5 "\"" + TOKEN_AND_AND@5..7 "&&" + NODE_IDENT@7..11 + TOKEN_IDENT@7..11 "true" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/has_attr_prec.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/has_attr_prec.nix new file mode 100644 index 0000000..6680262 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/has_attr_prec.nix @@ -0,0 +1 @@ +a?"b"&&true diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/if_elseif_else.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/if_elseif_else.expect new file mode 100644 index 0000000..e898f45 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/if_elseif_else.expect @@ -0,0 +1,30 @@ +NODE_ROOT@0..44 + NODE_IF_ELSE@0..44 + TOKEN_IF@0..2 "if" + TOKEN_WHITESPACE@2..3 " " + NODE_IDENT@3..8 + TOKEN_IDENT@3..8 "false" + TOKEN_WHITESPACE@8..9 " " + TOKEN_THEN@9..13 "then" + TOKEN_WHITESPACE@13..14 " " + NODE_LITERAL@14..15 + TOKEN_INTEGER@14..15 "1" + TOKEN_WHITESPACE@15..16 " " + TOKEN_ELSE@16..20 "else" + TOKEN_WHITESPACE@20..21 " " + NODE_IF_ELSE@21..44 + TOKEN_IF@21..23 "if" + TOKEN_WHITESPACE@23..24 " " + NODE_IDENT@24..28 + TOKEN_IDENT@24..28 "true" + TOKEN_WHITESPACE@28..29 " " + TOKEN_THEN@29..33 "then" + TOKEN_WHITESPACE@33..34 " " + NODE_IDENT@34..37 + TOKEN_IDENT@34..37 "two" + TOKEN_WHITESPACE@37..38 " " + TOKEN_ELSE@38..42 "else" + TOKEN_WHITESPACE@42..43 " " + NODE_LITERAL@43..44 + TOKEN_INTEGER@43..44 "3" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/if_elseif_else.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/if_elseif_else.nix new file mode 100644 index 0000000..c518629 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/if_elseif_else.nix @@ -0,0 +1 @@ +if false then 1 else if true then two else 3 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/import_nixpkgs.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/import_nixpkgs.expect new file mode 100644 index 0000000..63e65bf --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/import_nixpkgs.expect @@ -0,0 +1,11 @@ +NODE_ROOT@0..17 + NODE_APPLY@0..17 + NODE_APPLY@0..15 + NODE_IDENT@0..6 + TOKEN_IDENT@0..6 "import" + NODE_PATH_SEARCH@6..15 + TOKEN_PATH_SEARCH@6..15 "" + NODE_ATTR_SET@15..17 + TOKEN_L_BRACE@15..16 "{" + TOKEN_R_BRACE@16..17 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/import_nixpkgs.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/import_nixpkgs.nix new file mode 100644 index 0000000..83277f5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/import_nixpkgs.nix @@ -0,0 +1 @@ +import{} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit.expect new file mode 100644 index 0000000..42b13ef --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit.expect @@ -0,0 +1,102 @@ +NODE_ROOT@0..96 + NODE_LET_IN@0..96 + TOKEN_LET@0..3 "let" + TOKEN_WHITESPACE@3..6 "\n " + NODE_ATTRPATH_VALUE@6..12 + NODE_ATTRPATH@6..7 + NODE_IDENT@6..7 + TOKEN_IDENT@6..7 "y" + TOKEN_WHITESPACE@7..8 " " + TOKEN_ASSIGN@8..9 "=" + TOKEN_WHITESPACE@9..10 " " + NODE_LITERAL@10..11 + TOKEN_INTEGER@10..11 "2" + TOKEN_SEMICOLON@11..12 ";" + TOKEN_WHITESPACE@12..15 "\n " + NODE_ATTRPATH_VALUE@15..46 + NODE_ATTRPATH@15..18 + NODE_IDENT@15..18 + TOKEN_IDENT@15..18 "set" + TOKEN_WHITESPACE@18..19 " " + TOKEN_ASSIGN@19..20 "=" + TOKEN_WHITESPACE@20..21 " " + NODE_ATTR_SET@21..45 + TOKEN_L_BRACE@21..22 "{" + TOKEN_WHITESPACE@22..23 " " + NODE_ATTRPATH_VALUE@23..29 + NODE_ATTRPATH@23..24 + NODE_IDENT@23..24 + TOKEN_IDENT@23..24 "z" + TOKEN_WHITESPACE@24..25 " " + TOKEN_ASSIGN@25..26 "=" + TOKEN_WHITESPACE@26..27 " " + NODE_LITERAL@27..28 + TOKEN_INTEGER@27..28 "3" + TOKEN_SEMICOLON@28..29 ";" + TOKEN_WHITESPACE@29..30 " " + NODE_ATTRPATH_VALUE@30..36 + NODE_ATTRPATH@30..31 + NODE_IDENT@30..31 + TOKEN_IDENT@30..31 "a" + TOKEN_WHITESPACE@31..32 " " + TOKEN_ASSIGN@32..33 "=" + TOKEN_WHITESPACE@33..34 " " + NODE_LITERAL@34..35 + TOKEN_INTEGER@34..35 "4" + TOKEN_SEMICOLON@35..36 ";" + TOKEN_WHITESPACE@36..37 " " + NODE_ATTRPATH_VALUE@37..43 + NODE_ATTRPATH@37..38 + NODE_IDENT@37..38 + TOKEN_IDENT@37..38 "b" + TOKEN_WHITESPACE@38..39 " " + TOKEN_ASSIGN@39..40 "=" + TOKEN_WHITESPACE@40..41 " " + NODE_LITERAL@41..42 + TOKEN_INTEGER@41..42 "5" + TOKEN_SEMICOLON@42..43 ";" + TOKEN_WHITESPACE@43..44 " " + TOKEN_R_BRACE@44..45 "}" + TOKEN_SEMICOLON@45..46 ";" + TOKEN_WHITESPACE@46..47 "\n" + TOKEN_IN@47..49 "in" + TOKEN_WHITESPACE@49..50 " " + NODE_ATTR_SET@50..96 + TOKEN_L_BRACE@50..51 "{" + TOKEN_WHITESPACE@51..54 "\n " + NODE_ATTRPATH_VALUE@54..60 + NODE_ATTRPATH@54..55 + NODE_IDENT@54..55 + TOKEN_IDENT@54..55 "x" + TOKEN_WHITESPACE@55..56 " " + TOKEN_ASSIGN@56..57 "=" + TOKEN_WHITESPACE@57..58 " " + NODE_LITERAL@58..59 + TOKEN_INTEGER@58..59 "1" + TOKEN_SEMICOLON@59..60 ";" + TOKEN_WHITESPACE@60..63 "\n " + NODE_INHERIT@63..73 + TOKEN_INHERIT@63..70 "inherit" + TOKEN_WHITESPACE@70..71 " " + NODE_IDENT@71..72 + TOKEN_IDENT@71..72 "y" + TOKEN_SEMICOLON@72..73 ";" + TOKEN_WHITESPACE@73..76 "\n " + NODE_INHERIT@76..94 + TOKEN_INHERIT@76..83 "inherit" + TOKEN_WHITESPACE@83..84 " " + NODE_INHERIT_FROM@84..89 + TOKEN_L_PAREN@84..85 "(" + NODE_IDENT@85..88 + TOKEN_IDENT@85..88 "set" + TOKEN_R_PAREN@88..89 ")" + TOKEN_WHITESPACE@89..90 " " + NODE_IDENT@90..91 + TOKEN_IDENT@90..91 "z" + TOKEN_WHITESPACE@91..92 " " + NODE_IDENT@92..93 + TOKEN_IDENT@92..93 "a" + TOKEN_SEMICOLON@93..94 ";" + TOKEN_WHITESPACE@94..95 "\n" + TOKEN_R_BRACE@95..96 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit.nix new file mode 100644 index 0000000..62213a9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit.nix @@ -0,0 +1,8 @@ +let + y = 2; + set = { z = 3; a = 4; b = 5; }; +in { + x = 1; + inherit y; + inherit (set) z a; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit_dynamic.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit_dynamic.expect new file mode 100644 index 0000000..5bf96e8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit_dynamic.expect @@ -0,0 +1,77 @@ +NODE_ROOT@0..95 + NODE_ATTR_SET@0..95 + TOKEN_L_BRACE@0..1 "{" + NODE_ATTRPATH_VALUE@1..5 + NODE_ATTRPATH@1..2 + NODE_IDENT@1..2 + TOKEN_IDENT@1..2 "a" + TOKEN_ASSIGN@2..3 "=" + NODE_LITERAL@3..4 + TOKEN_INTEGER@3..4 "1" + TOKEN_SEMICOLON@4..5 ";" + NODE_INHERIT@5..17 + TOKEN_INHERIT@5..12 "inherit" + TOKEN_WHITESPACE@12..13 " " + NODE_IDENT@13..14 + TOKEN_IDENT@13..14 "b" + TOKEN_WHITESPACE@14..15 " " + NODE_IDENT@15..16 + TOKEN_IDENT@15..16 "c" + TOKEN_SEMICOLON@16..17 ";" + NODE_INHERIT@17..35 + TOKEN_INHERIT@17..24 "inherit" + TOKEN_WHITESPACE@24..25 " " + NODE_INHERIT_FROM@25..30 + TOKEN_L_PAREN@25..26 "(" + NODE_IDENT@26..29 + TOKEN_IDENT@26..29 "set" + TOKEN_R_PAREN@29..30 ")" + TOKEN_WHITESPACE@30..31 " " + NODE_IDENT@31..32 + TOKEN_IDENT@31..32 "d" + TOKEN_WHITESPACE@32..33 " " + NODE_IDENT@33..34 + TOKEN_IDENT@33..34 "e" + TOKEN_SEMICOLON@34..35 ";" + TOKEN_WHITESPACE@35..36 " " + NODE_INHERIT@36..51 + TOKEN_INHERIT@36..43 "inherit" + TOKEN_WHITESPACE@43..44 " " + NODE_DYNAMIC@44..50 + TOKEN_INTERPOL_START@44..46 "${" + NODE_STRING@46..49 + TOKEN_STRING_START@46..47 "\"" + TOKEN_STRING_CONTENT@47..48 "f" + TOKEN_STRING_END@48..49 "\"" + TOKEN_INTERPOL_END@49..50 "}" + TOKEN_SEMICOLON@50..51 ";" + TOKEN_WHITESPACE@51..52 " " + NODE_INHERIT@52..66 + TOKEN_INHERIT@52..59 "inherit" + TOKEN_WHITESPACE@59..60 " " + NODE_STRING@60..65 + TOKEN_STRING_START@60..61 "\"" + TOKEN_STRING_CONTENT@61..64 "foo" + TOKEN_STRING_END@64..65 "\"" + TOKEN_SEMICOLON@65..66 ";" + TOKEN_WHITESPACE@66..67 " " + NODE_INHERIT@67..85 + TOKEN_INHERIT@67..74 "inherit" + TOKEN_WHITESPACE@74..75 " " + NODE_INHERIT_FROM@75..78 + TOKEN_L_PAREN@75..76 "(" + NODE_IDENT@76..77 + TOKEN_IDENT@76..77 "a" + TOKEN_R_PAREN@77..78 ")" + TOKEN_WHITESPACE@78..79 " " + NODE_STRING@79..84 + TOKEN_STRING_START@79..80 "\"" + TOKEN_STRING_CONTENT@80..83 "bar" + TOKEN_STRING_END@83..84 "\"" + TOKEN_SEMICOLON@84..85 ";" + TOKEN_WHITESPACE@85..86 " " + NODE_INHERIT@86..94 + TOKEN_INHERIT@86..93 "inherit" + TOKEN_SEMICOLON@93..94 ";" + TOKEN_R_BRACE@94..95 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit_dynamic.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit_dynamic.nix new file mode 100644 index 0000000..9585768 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/inherit_dynamic.nix @@ -0,0 +1 @@ +{a=1;inherit b c;inherit (set) d e; inherit ${"f"}; inherit "foo"; inherit (a) "bar"; inherit;} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/interpolation.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/interpolation.expect new file mode 100644 index 0000000..6363af7 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/interpolation.expect @@ -0,0 +1,107 @@ +NODE_ROOT@0..270 + NODE_LET_IN@0..270 + TOKEN_LET@0..3 "let" + TOKEN_WHITESPACE@3..6 "\n " + NODE_ATTRPATH_VALUE@6..22 + NODE_ATTRPATH@6..11 + NODE_IDENT@6..11 + TOKEN_IDENT@6..11 "world" + TOKEN_WHITESPACE@11..12 " " + TOKEN_ASSIGN@12..13 "=" + TOKEN_WHITESPACE@13..14 " " + NODE_STRING@14..21 + TOKEN_STRING_START@14..15 "\"" + TOKEN_STRING_CONTENT@15..20 "World" + TOKEN_STRING_END@20..21 "\"" + TOKEN_SEMICOLON@21..22 ";" + TOKEN_WHITESPACE@22..23 "\n" + TOKEN_IN@23..25 "in" + TOKEN_WHITESPACE@25..26 " " + NODE_ATTR_SET@26..270 + TOKEN_L_BRACE@26..27 "{" + TOKEN_WHITESPACE@27..30 "\n " + NODE_ATTRPATH_VALUE@30..57 + NODE_ATTRPATH@30..36 + NODE_IDENT@30..36 + TOKEN_IDENT@30..36 "string" + TOKEN_WHITESPACE@36..37 " " + TOKEN_ASSIGN@37..38 "=" + TOKEN_WHITESPACE@38..39 " " + NODE_STRING@39..56 + TOKEN_STRING_START@39..40 "\"" + TOKEN_STRING_CONTENT@40..46 "Hello " + NODE_INTERPOL@46..54 + TOKEN_INTERPOL_START@46..48 "${" + NODE_IDENT@48..53 + TOKEN_IDENT@48..53 "world" + TOKEN_INTERPOL_END@53..54 "}" + TOKEN_STRING_CONTENT@54..55 "!" + TOKEN_STRING_END@55..56 "\"" + TOKEN_SEMICOLON@56..57 ";" + TOKEN_WHITESPACE@57..60 "\n " + NODE_ATTRPATH_VALUE@60..268 + NODE_ATTRPATH@60..69 + NODE_IDENT@60..69 + TOKEN_IDENT@60..69 "multiline" + TOKEN_WHITESPACE@69..70 " " + TOKEN_ASSIGN@70..71 "=" + TOKEN_WHITESPACE@71..72 " " + NODE_STRING@72..267 + TOKEN_STRING_START@72..74 "''" + TOKEN_STRING_CONTENT@74..101 "\n The set's x valu ..." + NODE_INTERPOL@101..161 + TOKEN_INTERPOL_START@101..103 "${" + TOKEN_WHITESPACE@103..110 "\n " + NODE_SELECT@110..155 + NODE_ATTR_SET@110..153 + TOKEN_L_BRACE@110..111 "{" + TOKEN_WHITESPACE@111..120 "\n " + NODE_ATTRPATH_VALUE@120..128 + NODE_ATTRPATH@120..121 + NODE_IDENT@120..121 + TOKEN_IDENT@120..121 "x" + TOKEN_WHITESPACE@121..122 " " + TOKEN_ASSIGN@122..123 "=" + TOKEN_WHITESPACE@123..124 " " + NODE_STRING@124..127 + TOKEN_STRING_START@124..125 "\"" + TOKEN_STRING_CONTENT@125..126 "1" + TOKEN_STRING_END@126..127 "\"" + TOKEN_SEMICOLON@127..128 ";" + TOKEN_WHITESPACE@128..137 "\n " + NODE_ATTRPATH_VALUE@137..145 + NODE_ATTRPATH@137..138 + NODE_IDENT@137..138 + TOKEN_IDENT@137..138 "y" + TOKEN_WHITESPACE@138..139 " " + TOKEN_ASSIGN@139..140 "=" + TOKEN_WHITESPACE@140..141 " " + NODE_STRING@141..144 + TOKEN_STRING_START@141..142 "\"" + TOKEN_STRING_CONTENT@142..143 "2" + TOKEN_STRING_END@143..144 "\"" + TOKEN_SEMICOLON@144..145 ";" + TOKEN_WHITESPACE@145..152 "\n " + TOKEN_R_BRACE@152..153 "}" + TOKEN_DOT@153..154 "." + NODE_ATTRPATH@154..155 + NODE_IDENT@154..155 + TOKEN_IDENT@154..155 "x" + TOKEN_WHITESPACE@155..160 "\n " + TOKEN_INTERPOL_END@160..161 "}" + TOKEN_STRING_CONTENT@161..253 "\n\n This line shall ..." + NODE_INTERPOL@253..262 + TOKEN_INTERPOL_START@253..255 "${" + TOKEN_WHITESPACE@255..256 " " + NODE_STRING@256..260 + TOKEN_STRING_START@256..257 "\"" + TOKEN_STRING_CONTENT@257..259 "hi" + TOKEN_STRING_END@259..260 "\"" + TOKEN_WHITESPACE@260..261 " " + TOKEN_INTERPOL_END@261..262 "}" + TOKEN_STRING_CONTENT@262..265 "\n " + TOKEN_STRING_END@265..267 "''" + TOKEN_SEMICOLON@267..268 ";" + TOKEN_WHITESPACE@268..269 "\n" + TOKEN_R_BRACE@269..270 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/interpolation.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/interpolation.nix new file mode 100644 index 0000000..dba4964 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/interpolation.nix @@ -0,0 +1,18 @@ +let + world = "World"; +in { + string = "Hello ${world}!"; + multiline = '' + The set's x value is: ${ + { + x = "1"; + y = "2"; + }.x + } + + This line shall have no indention + This line shall be indented by 2 + ''\n + ${ "hi" } + ''; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_is_not_uri.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_is_not_uri.expect new file mode 100644 index 0000000..7d2b806 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_is_not_uri.expect @@ -0,0 +1,9 @@ +NODE_ROOT@0..6 + NODE_LAMBDA@0..6 + NODE_IDENT_PARAM@0..1 + NODE_IDENT@0..1 + TOKEN_IDENT@0..1 "_" + TOKEN_COLON@1..2 ":" + NODE_IDENT@2..6 + TOKEN_IDENT@2..6 "null" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_is_not_uri.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_is_not_uri.nix new file mode 100644 index 0000000..1dd26eb --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_is_not_uri.nix @@ -0,0 +1 @@ +_:null \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_list.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_list.expect new file mode 100644 index 0000000..e714fa8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_list.expect @@ -0,0 +1,14 @@ +NODE_ROOT@0..7 + NODE_LAMBDA@0..7 + NODE_IDENT_PARAM@0..1 + NODE_IDENT@0..1 + TOKEN_IDENT@0..1 "m" + TOKEN_COLON@1..2 ":" + NODE_LIST@2..7 + TOKEN_L_BRACK@2..3 "[" + TOKEN_WHITESPACE@3..4 " " + NODE_IDENT@4..5 + TOKEN_IDENT@4..5 "m" + TOKEN_WHITESPACE@5..6 " " + TOKEN_R_BRACK@6..7 "]" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_list.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_list.nix new file mode 100644 index 0000000..9454eee --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_list.nix @@ -0,0 +1 @@ +m:[ m ] diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_nested.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_nested.expect new file mode 100644 index 0000000..0c2ad7c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_nested.expect @@ -0,0 +1,22 @@ +NODE_ROOT@0..11 + NODE_LAMBDA@0..11 + NODE_IDENT_PARAM@0..1 + NODE_IDENT@0..1 + TOKEN_IDENT@0..1 "a" + TOKEN_COLON@1..2 ":" + TOKEN_WHITESPACE@2..3 " " + NODE_LAMBDA@3..11 + NODE_IDENT_PARAM@3..4 + NODE_IDENT@3..4 + TOKEN_IDENT@3..4 "b" + TOKEN_COLON@4..5 ":" + TOKEN_WHITESPACE@5..6 " " + NODE_BIN_OP@6..11 + NODE_IDENT@6..7 + TOKEN_IDENT@6..7 "a" + TOKEN_WHITESPACE@7..8 " " + TOKEN_ADD@8..9 "+" + TOKEN_WHITESPACE@9..10 " " + NODE_IDENT@10..11 + TOKEN_IDENT@10..11 "b" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_nested.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_nested.nix new file mode 100644 index 0000000..cef5868 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/lambda_nested.nix @@ -0,0 +1 @@ +a: b: a + b diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/let.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/let.expect new file mode 100644 index 0000000..be22049 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/let.expect @@ -0,0 +1,20 @@ +NODE_ROOT@0..16 + NODE_LET_IN@0..16 + TOKEN_LET@0..3 "let" + TOKEN_WHITESPACE@3..4 " " + NODE_ATTRPATH_VALUE@4..11 + NODE_ATTRPATH@4..5 + NODE_IDENT@4..5 + TOKEN_IDENT@4..5 "a" + TOKEN_WHITESPACE@5..6 " " + TOKEN_ASSIGN@6..7 "=" + TOKEN_WHITESPACE@7..8 " " + NODE_LITERAL@8..10 + TOKEN_INTEGER@8..10 "42" + TOKEN_SEMICOLON@10..11 ";" + TOKEN_WHITESPACE@11..12 " " + TOKEN_IN@12..14 "in" + TOKEN_WHITESPACE@14..15 " " + NODE_IDENT@15..16 + TOKEN_IDENT@15..16 "a" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/let.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/let.nix new file mode 100644 index 0000000..c5cc3f6 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/let.nix @@ -0,0 +1 @@ +let a = 42; in a diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/let_legacy.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/let_legacy.expect new file mode 100644 index 0000000..cd7f81c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/let_legacy.expect @@ -0,0 +1,22 @@ +NODE_ROOT@0..17 + NODE_LEGACY_LET@0..17 + TOKEN_LET@0..3 "let" + TOKEN_L_BRACE@3..4 "{" + NODE_ATTRPATH_VALUE@4..9 + NODE_ATTRPATH@4..5 + NODE_IDENT@4..5 + TOKEN_IDENT@4..5 "a" + TOKEN_ASSIGN@5..6 "=" + NODE_LITERAL@6..8 + TOKEN_INTEGER@6..8 "42" + TOKEN_SEMICOLON@8..9 ";" + NODE_ATTRPATH_VALUE@9..16 + NODE_ATTRPATH@9..13 + NODE_IDENT@9..13 + TOKEN_IDENT@9..13 "body" + TOKEN_ASSIGN@13..14 "=" + NODE_IDENT@14..15 + TOKEN_IDENT@14..15 "a" + TOKEN_SEMICOLON@15..16 ";" + TOKEN_R_BRACE@16..17 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/let_legacy.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/let_legacy.nix new file mode 100644 index 0000000..4878f07 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/let_legacy.nix @@ -0,0 +1 @@ +let{a=42;body=a;} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/list.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/list.expect new file mode 100644 index 0000000..31c86c5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/list.expect @@ -0,0 +1,18 @@ +NODE_ROOT@0..13 + NODE_LIST@0..13 + TOKEN_L_BRACK@0..1 "[" + NODE_IDENT@1..2 + TOKEN_IDENT@1..2 "a" + TOKEN_WHITESPACE@2..3 " " + NODE_LITERAL@3..4 + TOKEN_INTEGER@3..4 "2" + TOKEN_WHITESPACE@4..5 " " + NODE_LITERAL@5..6 + TOKEN_INTEGER@5..6 "3" + TOKEN_WHITESPACE@6..7 " " + NODE_STRING@7..12 + TOKEN_STRING_START@7..8 "\"" + TOKEN_STRING_CONTENT@8..11 "lol" + TOKEN_STRING_END@11..12 "\"" + TOKEN_R_BRACK@12..13 "]" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/list.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/list.nix new file mode 100644 index 0000000..29d1219 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/list.nix @@ -0,0 +1 @@ +[a 2 3 "lol"] diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/list_concat.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/list_concat.expect new file mode 100644 index 0000000..b43f4ce --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/list_concat.expect @@ -0,0 +1,21 @@ +NODE_ROOT@0..15 + NODE_BIN_OP@0..15 + NODE_LIST@0..3 + TOKEN_L_BRACK@0..1 "[" + NODE_LITERAL@1..2 + TOKEN_INTEGER@1..2 "1" + TOKEN_R_BRACK@2..3 "]" + TOKEN_CONCAT@3..5 "++" + NODE_BIN_OP@5..15 + NODE_LIST@5..10 + TOKEN_L_BRACK@5..6 "[" + NODE_IDENT@6..9 + TOKEN_IDENT@6..9 "two" + TOKEN_R_BRACK@9..10 "]" + TOKEN_CONCAT@10..12 "++" + NODE_LIST@12..15 + TOKEN_L_BRACK@12..13 "[" + NODE_LITERAL@13..14 + TOKEN_INTEGER@13..14 "3" + TOKEN_R_BRACK@14..15 "]" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/list_concat.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/list_concat.nix new file mode 100644 index 0000000..12f79d0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/list_concat.nix @@ -0,0 +1 @@ +[1]++[two]++[3] diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/math.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/math.expect new file mode 100644 index 0000000..6aef926 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/math.expect @@ -0,0 +1,37 @@ +NODE_ROOT@0..23 + NODE_BIN_OP@0..23 + NODE_BIN_OP@0..9 + NODE_LITERAL@0..1 + TOKEN_INTEGER@0..1 "1" + TOKEN_WHITESPACE@1..2 " " + TOKEN_ADD@2..3 "+" + TOKEN_WHITESPACE@3..4 " " + NODE_BIN_OP@4..9 + NODE_LITERAL@4..5 + TOKEN_INTEGER@4..5 "2" + TOKEN_WHITESPACE@5..6 " " + TOKEN_MUL@6..7 "*" + TOKEN_WHITESPACE@7..8 " " + NODE_LITERAL@8..9 + TOKEN_INTEGER@8..9 "3" + TOKEN_WHITESPACE@9..10 " " + TOKEN_ADD@10..11 "+" + TOKEN_WHITESPACE@11..12 " " + NODE_BIN_OP@12..23 + NODE_LITERAL@12..13 + TOKEN_INTEGER@12..13 "4" + TOKEN_WHITESPACE@13..14 " " + TOKEN_DIV@14..15 "/" + TOKEN_WHITESPACE@15..16 " " + NODE_PAREN@16..23 + TOKEN_L_PAREN@16..17 "(" + NODE_BIN_OP@17..22 + NODE_LITERAL@17..18 + TOKEN_INTEGER@17..18 "5" + TOKEN_WHITESPACE@18..19 " " + TOKEN_SUB@19..20 "-" + TOKEN_WHITESPACE@20..21 " " + NODE_LITERAL@21..22 + TOKEN_INTEGER@21..22 "6" + TOKEN_R_PAREN@22..23 ")" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/math.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/math.nix new file mode 100644 index 0000000..0aacfdd --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/math.nix @@ -0,0 +1 @@ +1 + 2 * 3 + 4 / (5 - 6) diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/math2.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/math2.expect new file mode 100644 index 0000000..44cefb4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/math2.expect @@ -0,0 +1,22 @@ +NODE_ROOT@0..13 + NODE_BIN_OP@0..13 + NODE_BIN_OP@0..5 + NODE_LITERAL@0..1 + TOKEN_INTEGER@0..1 "1" + TOKEN_WHITESPACE@1..2 " " + TOKEN_ADD@2..3 "+" + TOKEN_WHITESPACE@3..4 " " + NODE_LITERAL@4..5 + TOKEN_INTEGER@4..5 "2" + TOKEN_WHITESPACE@5..6 " " + TOKEN_ADD@6..7 "+" + TOKEN_WHITESPACE@7..8 " " + NODE_BIN_OP@8..13 + NODE_LITERAL@8..9 + TOKEN_INTEGER@8..9 "3" + TOKEN_WHITESPACE@9..10 " " + TOKEN_MUL@10..11 "*" + TOKEN_WHITESPACE@11..12 " " + NODE_LITERAL@12..13 + TOKEN_INTEGER@12..13 "4" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/math2.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/math2.nix new file mode 100644 index 0000000..f627523 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/math2.nix @@ -0,0 +1 @@ +1 + 2 + 3 * 4 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/math_no_ws.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/math_no_ws.expect new file mode 100644 index 0000000..68006b8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/math_no_ws.expect @@ -0,0 +1,17 @@ +NODE_ROOT@0..8 + NODE_BIN_OP@0..8 + NODE_LITERAL@0..1 + TOKEN_INTEGER@0..1 "5" + TOKEN_MUL@1..2 "*" + NODE_UNARY_OP@2..8 + TOKEN_SUB@2..3 "-" + NODE_PAREN@3..8 + TOKEN_L_PAREN@3..4 "(" + NODE_BIN_OP@4..7 + NODE_LITERAL@4..5 + TOKEN_INTEGER@4..5 "3" + TOKEN_SUB@5..6 "-" + NODE_LITERAL@6..7 + TOKEN_INTEGER@6..7 "2" + TOKEN_R_PAREN@7..8 ")" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/math_no_ws.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/math_no_ws.nix new file mode 100644 index 0000000..252eef9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/math_no_ws.nix @@ -0,0 +1 @@ +5*-(3-2) diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/merge.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/merge.expect new file mode 100644 index 0000000..3fa60fb --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/merge.expect @@ -0,0 +1,26 @@ +NODE_ROOT@0..14 + NODE_BIN_OP@0..14 + NODE_ATTR_SET@0..6 + TOKEN_L_BRACE@0..1 "{" + NODE_ATTRPATH_VALUE@1..5 + NODE_ATTRPATH@1..2 + NODE_IDENT@1..2 + TOKEN_IDENT@1..2 "a" + TOKEN_ASSIGN@2..3 "=" + NODE_LITERAL@3..4 + TOKEN_INTEGER@3..4 "1" + TOKEN_SEMICOLON@4..5 ";" + TOKEN_R_BRACE@5..6 "}" + TOKEN_UPDATE@6..8 "//" + NODE_ATTR_SET@8..14 + TOKEN_L_BRACE@8..9 "{" + NODE_ATTRPATH_VALUE@9..13 + NODE_ATTRPATH@9..10 + NODE_IDENT@9..10 + TOKEN_IDENT@9..10 "b" + TOKEN_ASSIGN@10..11 "=" + NODE_LITERAL@11..12 + TOKEN_INTEGER@11..12 "2" + TOKEN_SEMICOLON@12..13 ";" + TOKEN_R_BRACE@13..14 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/merge.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/merge.nix new file mode 100644 index 0000000..b8c3c88 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/merge.nix @@ -0,0 +1 @@ +{a=1;}//{b=2;} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/multiple.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/multiple.expect new file mode 100644 index 0000000..347995d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/multiple.expect @@ -0,0 +1,24 @@ +NODE_ROOT@0..15 + NODE_HAS_ATTR@0..15 + NODE_HAS_ATTR@0..6 + NODE_ATTR_SET@0..2 + TOKEN_L_BRACE@0..1 "{" + TOKEN_R_BRACE@1..2 "}" + TOKEN_WHITESPACE@2..3 " " + TOKEN_QUESTION@3..4 "?" + TOKEN_WHITESPACE@4..5 " " + NODE_ATTRPATH@5..6 + NODE_IDENT@5..6 + TOKEN_IDENT@5..6 "a" + TOKEN_WHITESPACE@6..7 " " + TOKEN_QUESTION@7..8 "?" + TOKEN_WHITESPACE@8..9 " " + NODE_ATTRPATH@9..15 + NODE_DYNAMIC@9..15 + TOKEN_INTERPOL_START@9..11 "${" + NODE_STRING@11..14 + TOKEN_STRING_START@11..12 "\"" + TOKEN_STRING_CONTENT@12..13 "a" + TOKEN_STRING_END@13..14 "\"" + TOKEN_INTERPOL_END@14..15 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/multiple.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/multiple.nix new file mode 100644 index 0000000..976ec7c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/multiple.nix @@ -0,0 +1 @@ +{} ? a ? ${"a"} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/number_list.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/number_list.expect new file mode 100644 index 0000000..2e7247f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/number_list.expect @@ -0,0 +1,15 @@ +NODE_ROOT@0..17 + NODE_LIST@0..17 + TOKEN_L_BRACK@0..1 "[" + NODE_LITERAL@1..4 + TOKEN_INTEGER@1..4 "001" + NODE_LITERAL@4..10 + TOKEN_FLOAT@4..10 ".22e01" + NODE_IDENT@10..11 + TOKEN_IDENT@10..11 "e" + NODE_LITERAL@11..14 + TOKEN_FLOAT@11..14 ".30" + NODE_LITERAL@14..16 + TOKEN_FLOAT@14..16 ".4" + TOKEN_R_BRACK@16..17 "]" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/number_list.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/number_list.nix new file mode 100644 index 0000000..89f33f4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/number_list.nix @@ -0,0 +1 @@ +[001.22e01e.30.4] \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/operators_right_assoc.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/operators_right_assoc.expect new file mode 100644 index 0000000..072d393 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/operators_right_assoc.expect @@ -0,0 +1,84 @@ +NODE_ROOT@0..71 + NODE_LIST@0..71 + TOKEN_L_BRACK@0..1 "[" + TOKEN_WHITESPACE@1..4 "\n " + NODE_PAREN@4..17 + TOKEN_L_PAREN@4..5 "(" + NODE_BIN_OP@5..16 + NODE_IDENT@5..6 + TOKEN_IDENT@5..6 "a" + TOKEN_WHITESPACE@6..7 " " + TOKEN_IMPLICATION@7..9 "->" + TOKEN_WHITESPACE@9..10 " " + NODE_BIN_OP@10..16 + NODE_IDENT@10..11 + TOKEN_IDENT@10..11 "b" + TOKEN_WHITESPACE@11..12 " " + TOKEN_IMPLICATION@12..14 "->" + TOKEN_WHITESPACE@14..15 " " + NODE_IDENT@15..16 + TOKEN_IDENT@15..16 "c" + TOKEN_R_PAREN@16..17 ")" + TOKEN_WHITESPACE@17..20 "\n " + NODE_PAREN@20..33 + TOKEN_L_PAREN@20..21 "(" + NODE_BIN_OP@21..32 + NODE_IDENT@21..22 + TOKEN_IDENT@21..22 "a" + TOKEN_WHITESPACE@22..23 " " + TOKEN_CONCAT@23..25 "++" + TOKEN_WHITESPACE@25..26 " " + NODE_BIN_OP@26..32 + NODE_IDENT@26..27 + TOKEN_IDENT@26..27 "b" + TOKEN_WHITESPACE@27..28 " " + TOKEN_CONCAT@28..30 "++" + TOKEN_WHITESPACE@30..31 " " + NODE_IDENT@31..32 + TOKEN_IDENT@31..32 "c" + TOKEN_R_PAREN@32..33 ")" + TOKEN_WHITESPACE@33..36 "\n " + NODE_PAREN@36..49 + TOKEN_L_PAREN@36..37 "(" + NODE_BIN_OP@37..48 + NODE_IDENT@37..38 + TOKEN_IDENT@37..38 "a" + TOKEN_WHITESPACE@38..39 " " + TOKEN_UPDATE@39..41 "//" + TOKEN_WHITESPACE@41..42 " " + NODE_BIN_OP@42..48 + NODE_IDENT@42..43 + TOKEN_IDENT@42..43 "b" + TOKEN_WHITESPACE@43..44 " " + TOKEN_UPDATE@44..46 "//" + TOKEN_WHITESPACE@46..47 " " + NODE_IDENT@47..48 + TOKEN_IDENT@47..48 "c" + TOKEN_R_PAREN@48..49 ")" + TOKEN_WHITESPACE@49..52 "\n " + NODE_PAREN@52..69 + TOKEN_L_PAREN@52..53 "(" + NODE_BIN_OP@53..68 + NODE_BIN_OP@53..63 + NODE_BIN_OP@53..58 + NODE_IDENT@53..54 + TOKEN_IDENT@53..54 "a" + TOKEN_WHITESPACE@54..55 " " + TOKEN_ADD@55..56 "+" + TOKEN_WHITESPACE@56..57 " " + NODE_IDENT@57..58 + TOKEN_IDENT@57..58 "b" + TOKEN_WHITESPACE@58..59 " " + TOKEN_UPDATE@59..61 "//" + TOKEN_WHITESPACE@61..62 " " + NODE_IDENT@62..63 + TOKEN_IDENT@62..63 "c" + TOKEN_WHITESPACE@63..64 " " + TOKEN_IMPLICATION@64..66 "->" + TOKEN_WHITESPACE@66..67 " " + NODE_IDENT@67..68 + TOKEN_IDENT@67..68 "d" + TOKEN_R_PAREN@68..69 ")" + TOKEN_WHITESPACE@69..70 "\n" + TOKEN_R_BRACK@70..71 "]" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/operators_right_assoc.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/operators_right_assoc.nix new file mode 100644 index 0000000..3fd18ff --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/operators_right_assoc.nix @@ -0,0 +1,6 @@ +[ + (a -> b -> c) + (a ++ b ++ c) + (a // b // c) + (a + b // c -> d) +] diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/or-as-ident.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/or-as-ident.expect new file mode 100644 index 0000000..402e9f5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/or-as-ident.expect @@ -0,0 +1,18 @@ +NODE_ROOT@0..136 + TOKEN_COMMENT@0..117 "# https://github.com/ ..." + TOKEN_WHITESPACE@117..118 "\n" + NODE_APPLY@118..136 + NODE_APPLY@118..130 + NODE_IDENT@118..121 + TOKEN_IDENT@118..121 "foo" + TOKEN_WHITESPACE@121..122 " " + NODE_APPLY@122..130 + NODE_IDENT@122..127 + TOKEN_IDENT@122..127 "foldl" + TOKEN_WHITESPACE@127..128 " " + NODE_IDENT@128..130 + TOKEN_IDENT@128..130 "or" + TOKEN_WHITESPACE@130..131 " " + NODE_IDENT@131..136 + TOKEN_IDENT@131..136 "false" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/or-as-ident.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/or-as-ident.nix new file mode 100644 index 0000000..7cbc228 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/or-as-ident.nix @@ -0,0 +1,2 @@ +# https://github.com/NixOS/nixpkgs/blob/38860c9e91cb00f4d8cd19c7b4e36c45680c89b5/nixos/modules/security/pam.nix#L1180 +foo foldl or false diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/or_in_attr.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/or_in_attr.expect new file mode 100644 index 0000000..e75a62d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/or_in_attr.expect @@ -0,0 +1,43 @@ +NODE_ROOT@0..37 + NODE_ATTR_SET@0..37 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..16 + NODE_ATTRPATH@4..9 + NODE_IDENT@4..5 + TOKEN_IDENT@4..5 "a" + TOKEN_DOT@5..6 "." + NODE_IDENT@6..7 + TOKEN_IDENT@6..7 "b" + TOKEN_DOT@7..8 "." + NODE_IDENT@8..9 + TOKEN_IDENT@8..9 "c" + TOKEN_WHITESPACE@9..10 " " + TOKEN_ASSIGN@10..11 "=" + TOKEN_WHITESPACE@11..12 " " + NODE_LITERAL@12..15 + TOKEN_INTEGER@12..15 "324" + TOKEN_SEMICOLON@15..16 ";" + TOKEN_WHITESPACE@16..19 "\n " + NODE_ATTRPATH_VALUE@19..35 + NODE_ATTRPATH@19..28 + NODE_IDENT@19..20 + TOKEN_IDENT@19..20 "a" + TOKEN_DOT@20..21 "." + NODE_IDENT@21..23 + TOKEN_IDENT@21..23 "or" + TOKEN_DOT@23..24 "." + NODE_IDENT@24..25 + TOKEN_IDENT@24..25 "b" + TOKEN_DOT@25..26 "." + NODE_IDENT@26..28 + TOKEN_IDENT@26..28 "or" + TOKEN_WHITESPACE@28..29 " " + TOKEN_ASSIGN@29..30 "=" + TOKEN_WHITESPACE@30..31 " " + NODE_LITERAL@31..34 + TOKEN_INTEGER@31..34 "234" + TOKEN_SEMICOLON@34..35 ";" + TOKEN_WHITESPACE@35..36 "\n" + TOKEN_R_BRACE@36..37 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/or_in_attr.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/or_in_attr.nix new file mode 100644 index 0000000..1e656f9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/or_in_attr.nix @@ -0,0 +1,4 @@ +{ + a.b.c = 324; + a.or.b.or = 234; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/path.expect new file mode 100644 index 0000000..febb49d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path.expect @@ -0,0 +1,50 @@ +NODE_ROOT@0..107 + NODE_ATTR_SET@0..107 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..21 + NODE_ATTRPATH@4..7 + NODE_IDENT@4..7 + TOKEN_IDENT@4..7 "abs" + TOKEN_WHITESPACE@7..8 " " + TOKEN_ASSIGN@8..9 "=" + TOKEN_WHITESPACE@9..10 " " + NODE_PATH_ABS@10..20 + TOKEN_PATH_ABS@10..20 "/nix/store" + TOKEN_SEMICOLON@20..21 ";" + TOKEN_WHITESPACE@21..24 "\n " + NODE_ATTRPATH_VALUE@24..50 + NODE_ATTRPATH@24..28 + NODE_IDENT@24..28 + TOKEN_IDENT@24..28 "home" + TOKEN_WHITESPACE@28..29 " " + TOKEN_ASSIGN@29..30 "=" + TOKEN_WHITESPACE@30..31 " " + NODE_PATH_HOME@31..49 + TOKEN_PATH_HOME@31..49 "~/.nix-profile/bin" + TOKEN_SEMICOLON@49..50 ";" + TOKEN_WHITESPACE@50..53 "\n " + NODE_ATTRPATH_VALUE@53..79 + NODE_ATTRPATH@53..56 + NODE_IDENT@53..56 + TOKEN_IDENT@53..56 "rel" + TOKEN_WHITESPACE@56..57 " " + TOKEN_ASSIGN@57..58 "=" + TOKEN_WHITESPACE@58..59 " " + NODE_PATH_REL@59..78 + TOKEN_PATH_REL@59..78 "./configuration.nix" + TOKEN_SEMICOLON@78..79 ";" + TOKEN_WHITESPACE@79..82 "\n " + NODE_ATTRPATH_VALUE@82..105 + NODE_ATTRPATH@82..87 + NODE_IDENT@82..87 + TOKEN_IDENT@82..87 "store" + TOKEN_WHITESPACE@87..88 " " + TOKEN_ASSIGN@88..89 "=" + TOKEN_WHITESPACE@89..90 " " + NODE_PATH_SEARCH@90..104 + TOKEN_PATH_SEARCH@90..104 "" + TOKEN_SEMICOLON@104..105 ";" + TOKEN_WHITESPACE@105..106 "\n" + TOKEN_R_BRACE@106..107 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/path.nix new file mode 100644 index 0000000..047ef48 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path.nix @@ -0,0 +1,6 @@ +{ + abs = /nix/store; + home = ~/.nix-profile/bin; + rel = ./configuration.nix; + store = ; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_abs_interp_start.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_abs_interp_start.expect new file mode 100644 index 0000000..b94b5aa --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_abs_interp_start.expect @@ -0,0 +1,9 @@ +NODE_ROOT@0..7 + NODE_PATH_ABS@0..7 + TOKEN_PATH_ABS@0..1 "/" + NODE_INTERPOL@1..7 + TOKEN_INTERPOL_START@1..3 "${" + NODE_IDENT@3..6 + TOKEN_IDENT@3..6 "foo" + TOKEN_INTERPOL_END@6..7 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_abs_interp_start.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_abs_interp_start.nix new file mode 100644 index 0000000..53f93f1 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_abs_interp_start.nix @@ -0,0 +1 @@ +/${foo} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_complex_mix.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_complex_mix.expect new file mode 100644 index 0000000..e4b0cdf --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_complex_mix.expect @@ -0,0 +1,142 @@ +NODE_ROOT@0..402 + NODE_ATTR_SET@0..402 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + TOKEN_COMMENT@4..36 "# Various path types ..." + TOKEN_WHITESPACE@36..39 "\n " + NODE_ATTRPATH_VALUE@39..72 + NODE_ATTRPATH@39..42 + NODE_IDENT@39..42 + TOKEN_IDENT@39..42 "abs" + TOKEN_WHITESPACE@42..43 " " + TOKEN_ASSIGN@43..44 "=" + TOKEN_WHITESPACE@44..45 " " + NODE_PATH_ABS@45..71 + TOKEN_PATH_ABS@45..71 "/nix/store/hash-name- ..." + TOKEN_SEMICOLON@71..72 ";" + TOKEN_WHITESPACE@72..75 "\n " + NODE_ATTRPATH_VALUE@75..98 + NODE_ATTRPATH@75..78 + NODE_IDENT@75..78 + TOKEN_IDENT@75..78 "rel" + TOKEN_WHITESPACE@78..79 " " + TOKEN_ASSIGN@79..80 "=" + TOKEN_WHITESPACE@80..81 " " + NODE_PATH_REL@81..97 + TOKEN_PATH_REL@81..97 "./foo/bar/../baz" + TOKEN_SEMICOLON@97..98 ";" + TOKEN_WHITESPACE@98..101 "\n " + NODE_ATTRPATH_VALUE@101..135 + NODE_ATTRPATH@101..105 + NODE_IDENT@101..105 + TOKEN_IDENT@101..105 "home" + TOKEN_WHITESPACE@105..106 " " + TOKEN_ASSIGN@106..107 "=" + TOKEN_WHITESPACE@107..108 " " + NODE_PATH_HOME@108..134 + TOKEN_PATH_HOME@108..134 "~/.config/nixpkgs/ove ..." + TOKEN_SEMICOLON@134..135 ";" + TOKEN_WHITESPACE@135..138 "\n " + NODE_ATTRPATH_VALUE@138..169 + NODE_ATTRPATH@138..144 + NODE_IDENT@138..144 + TOKEN_IDENT@138..144 "search" + TOKEN_WHITESPACE@144..145 " " + TOKEN_ASSIGN@145..146 "=" + TOKEN_WHITESPACE@146..147 " " + NODE_PATH_SEARCH@147..168 + TOKEN_PATH_SEARCH@147..168 "" + TOKEN_SEMICOLON@168..169 ";" + TOKEN_WHITESPACE@169..175 "\n \n " + TOKEN_COMMENT@175..206 "# Paths with special ..." + TOKEN_WHITESPACE@206..209 "\n " + NODE_ATTRPATH_VALUE@209..234 + NODE_ATTRPATH@209..220 + NODE_IDENT@209..220 + TOKEN_IDENT@209..220 "withNumbers" + TOKEN_WHITESPACE@220..221 " " + TOKEN_ASSIGN@221..222 "=" + TOKEN_WHITESPACE@222..223 " " + NODE_PATH_ABS@223..233 + TOKEN_PATH_ABS@223..233 "/usr/lib64" + TOKEN_SEMICOLON@233..234 ";" + TOKEN_WHITESPACE@234..237 "\n " + NODE_ATTRPATH_VALUE@237..262 + NODE_ATTRPATH@237..245 + NODE_IDENT@237..245 + TOKEN_IDENT@237..245 "withDots" + TOKEN_WHITESPACE@245..246 " " + TOKEN_ASSIGN@246..247 "=" + TOKEN_WHITESPACE@247..248 " " + NODE_PATH_REL@248..261 + TOKEN_PATH_REL@248..261 "./foo.bar.baz" + TOKEN_SEMICOLON@261..262 ";" + TOKEN_WHITESPACE@262..265 "\n " + NODE_ATTRPATH_VALUE@265..286 + NODE_ATTRPATH@265..273 + NODE_IDENT@265..273 + TOKEN_IDENT@265..273 "withPlus" + TOKEN_WHITESPACE@273..274 " " + TOKEN_ASSIGN@274..275 "=" + TOKEN_WHITESPACE@275..276 " " + NODE_PATH_REL@276..285 + TOKEN_PATH_REL@276..285 "./foo+bar" + TOKEN_SEMICOLON@285..286 ";" + TOKEN_WHITESPACE@286..289 "\n " + NODE_ATTRPATH_VALUE@289..319 + NODE_ATTRPATH@289..297 + NODE_IDENT@289..297 + TOKEN_IDENT@289..297 "withDash" + TOKEN_WHITESPACE@297..298 " " + TOKEN_ASSIGN@298..299 "=" + TOKEN_WHITESPACE@299..300 " " + NODE_PATH_ABS@300..318 + TOKEN_PATH_ABS@300..318 "/nix-store/package" + TOKEN_SEMICOLON@318..319 ";" + TOKEN_WHITESPACE@319..325 "\n \n " + TOKEN_COMMENT@325..342 "# Path operations" + TOKEN_WHITESPACE@342..345 "\n " + NODE_ATTRPATH_VALUE@345..369 + NODE_ATTRPATH@345..353 + NODE_IDENT@345..353 + TOKEN_IDENT@345..353 "combined" + TOKEN_WHITESPACE@353..354 " " + TOKEN_ASSIGN@354..355 "=" + TOKEN_WHITESPACE@355..356 " " + NODE_BIN_OP@356..368 + NODE_PATH_ABS@356..360 + TOKEN_PATH_ABS@356..360 "/foo" + TOKEN_WHITESPACE@360..361 " " + TOKEN_ADD@361..362 "+" + TOKEN_WHITESPACE@362..363 " " + NODE_PATH_REL@363..368 + TOKEN_PATH_REL@363..368 "./bar" + TOKEN_SEMICOLON@368..369 ";" + TOKEN_WHITESPACE@369..372 "\n " + NODE_ATTRPATH_VALUE@372..400 + NODE_ATTRPATH@372..378 + NODE_IDENT@372..378 + TOKEN_IDENT@372..378 "inList" + TOKEN_WHITESPACE@378..379 " " + TOKEN_ASSIGN@379..380 "=" + TOKEN_WHITESPACE@380..381 " " + NODE_LIST@381..399 + TOKEN_L_BRACK@381..382 "[" + TOKEN_WHITESPACE@382..383 " " + NODE_PATH_ABS@383..385 + TOKEN_PATH_ABS@383..385 "/a" + TOKEN_WHITESPACE@385..386 " " + NODE_PATH_REL@386..389 + TOKEN_PATH_REL@386..389 "./b" + TOKEN_WHITESPACE@389..390 " " + NODE_PATH_HOME@390..393 + TOKEN_PATH_HOME@390..393 "~/c" + TOKEN_WHITESPACE@393..394 " " + NODE_PATH_SEARCH@394..397 + TOKEN_PATH_SEARCH@394..397 "" + TOKEN_WHITESPACE@397..398 " " + TOKEN_R_BRACK@398..399 "]" + TOKEN_SEMICOLON@399..400 ";" + TOKEN_WHITESPACE@400..401 "\n" + TOKEN_R_BRACE@401..402 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_complex_mix.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_complex_mix.nix new file mode 100644 index 0000000..1397717 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_complex_mix.nix @@ -0,0 +1,17 @@ +{ + # Various path types in one file + abs = /nix/store/hash-name-1.0.0; + rel = ./foo/bar/../baz; + home = ~/.config/nixpkgs/overlays; + search = ; + + # Paths with special characters + withNumbers = /usr/lib64; + withDots = ./foo.bar.baz; + withPlus = ./foo+bar; + withDash = /nix-store/package; + + # Path operations + combined = /foo + ./bar; + inList = [ /a ./b ~/c ]; +} \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp.expect new file mode 100644 index 0000000..50c003b --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp.expect @@ -0,0 +1,82 @@ +NODE_ROOT@0..91 + NODE_LET_IN@0..91 + TOKEN_LET@0..3 "let" + TOKEN_WHITESPACE@3..6 "\n " + NODE_ATTRPATH_VALUE@6..29 + NODE_ATTRPATH@6..7 + NODE_IDENT@6..7 + TOKEN_IDENT@6..7 "a" + TOKEN_WHITESPACE@7..8 " " + TOKEN_ASSIGN@8..9 "=" + TOKEN_WHITESPACE@9..10 " " + NODE_LAMBDA@10..28 + NODE_IDENT_PARAM@10..11 + NODE_IDENT@10..11 + TOKEN_IDENT@10..11 "f" + TOKEN_COLON@11..12 ":" + TOKEN_WHITESPACE@12..13 " " + NODE_PATH_REL@13..28 + TOKEN_PATH_REL@13..18 "./foo" + NODE_INTERPOL@18..24 + TOKEN_INTERPOL_START@18..20 "${" + NODE_IDENT@20..23 + TOKEN_IDENT@20..23 "bar" + TOKEN_INTERPOL_END@23..24 "}" + TOKEN_PATH_REL@24..28 "/baz" + TOKEN_SEMICOLON@28..29 ";" + TOKEN_WHITESPACE@29..32 "\n " + NODE_ATTRPATH_VALUE@32..86 + NODE_ATTRPATH@32..33 + NODE_IDENT@32..33 + TOKEN_IDENT@32..33 "b" + TOKEN_WHITESPACE@33..34 " " + TOKEN_ASSIGN@34..35 "=" + TOKEN_WHITESPACE@35..36 " " + NODE_APPLY@36..85 + NODE_APPLY@36..66 + NODE_APPLY@36..53 + NODE_APPLY@36..43 + NODE_IDENT@36..37 + TOKEN_IDENT@36..37 "a" + TOKEN_WHITESPACE@37..38 " " + NODE_PATH_REL@38..43 + TOKEN_PATH_REL@38..43 "./bar" + TOKEN_WHITESPACE@43..44 " " + NODE_PATH_REL@44..53 + TOKEN_PATH_REL@44..49 "./baz" + NODE_INTERPOL@49..53 + TOKEN_INTERPOL_START@49..51 "${" + NODE_IDENT@51..52 + TOKEN_IDENT@51..52 "x" + TOKEN_INTERPOL_END@52..53 "}" + TOKEN_WHITESPACE@53..54 " " + NODE_PATH_REL@54..66 + TOKEN_PATH_REL@54..61 "./snens" + NODE_INTERPOL@61..65 + TOKEN_INTERPOL_START@61..63 "${" + NODE_IDENT@63..64 + TOKEN_IDENT@63..64 "x" + TOKEN_INTERPOL_END@64..65 "}" + TOKEN_PATH_REL@65..66 "y" + TOKEN_WHITESPACE@66..67 " " + NODE_PATH_REL@67..85 + TOKEN_PATH_REL@67..72 "./qux" + NODE_INTERPOL@72..76 + TOKEN_INTERPOL_START@72..74 "${" + NODE_IDENT@74..75 + TOKEN_IDENT@74..75 "x" + TOKEN_INTERPOL_END@75..76 "}" + TOKEN_PATH_REL@76..77 "." + NODE_INTERPOL@77..81 + TOKEN_INTERPOL_START@77..79 "${" + NODE_IDENT@79..80 + TOKEN_IDENT@79..80 "y" + TOKEN_INTERPOL_END@80..81 "}" + TOKEN_PATH_REL@81..85 ".z/w" + TOKEN_SEMICOLON@85..86 ";" + TOKEN_WHITESPACE@86..87 "\n" + TOKEN_IN@87..89 "in" + TOKEN_WHITESPACE@89..90 " " + NODE_IDENT@90..91 + TOKEN_IDENT@90..91 "b" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp.nix new file mode 100644 index 0000000..2d0e7a4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp.nix @@ -0,0 +1,4 @@ +let + a = f: ./foo${bar}/baz; + b = a ./bar ./baz${x} ./snens${x}y ./qux${x}.${y}.z/w; +in b diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp_no_prefix.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp_no_prefix.expect new file mode 100644 index 0000000..435a45c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp_no_prefix.expect @@ -0,0 +1,9 @@ +NODE_ROOT@0..6 + NODE_PATH_REL@0..6 + TOKEN_PATH_REL@0..2 "a/" + NODE_INTERPOL@2..6 + TOKEN_INTERPOL_START@2..4 "${" + NODE_IDENT@4..5 + TOKEN_IDENT@4..5 "b" + TOKEN_INTERPOL_END@5..6 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp_no_prefix.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp_no_prefix.nix new file mode 100644 index 0000000..1527272 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_interp_no_prefix.nix @@ -0,0 +1 @@ +a/${b} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_no_newline.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_no_newline.expect new file mode 100644 index 0000000..f4336ab --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_no_newline.expect @@ -0,0 +1,9 @@ +NODE_ROOT@0..11 + NODE_APPLY@0..10 + NODE_IDENT@0..6 + TOKEN_IDENT@0..6 "import" + TOKEN_WHITESPACE@6..7 " " + NODE_PATH_REL@7..10 + TOKEN_PATH_REL@7..10 "./." + TOKEN_WHITESPACE@10..11 "\n" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/path_no_newline.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_no_newline.nix new file mode 100644 index 0000000..2c18eb4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/path_no_newline.nix @@ -0,0 +1,2 @@ +import ./. + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_left.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_left.expect new file mode 100644 index 0000000..d6aed25 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_left.expect @@ -0,0 +1,21 @@ +NODE_ROOT@0..20 + NODE_LAMBDA@0..20 + NODE_PATTERN@0..13 + NODE_PAT_BIND@0..7 + NODE_IDENT@0..5 + TOKEN_IDENT@0..5 "outer" + TOKEN_WHITESPACE@5..6 " " + TOKEN_AT@6..7 "@" + TOKEN_WHITESPACE@7..8 " " + TOKEN_L_BRACE@8..9 "{" + TOKEN_WHITESPACE@9..10 " " + NODE_PAT_ENTRY@10..11 + NODE_IDENT@10..11 + TOKEN_IDENT@10..11 "a" + TOKEN_WHITESPACE@11..12 " " + TOKEN_R_BRACE@12..13 "}" + TOKEN_COLON@13..14 ":" + TOKEN_WHITESPACE@14..15 " " + NODE_IDENT@15..20 + TOKEN_IDENT@15..20 "outer" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_left.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_left.nix new file mode 100644 index 0000000..fca3e5f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_left.nix @@ -0,0 +1 @@ +outer @ { a }: outer diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_right.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_right.expect new file mode 100644 index 0000000..8ff6468 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_right.expect @@ -0,0 +1,16 @@ +NODE_ROOT@0..13 + NODE_LAMBDA@0..13 + NODE_PATTERN@0..10 + TOKEN_L_BRACE@0..1 "{" + TOKEN_R_BRACE@1..2 "}" + TOKEN_WHITESPACE@2..3 " " + NODE_PAT_BIND@3..10 + TOKEN_AT@3..4 "@" + TOKEN_WHITESPACE@4..5 " " + NODE_IDENT@5..10 + TOKEN_IDENT@5..10 "outer" + TOKEN_COLON@10..11 ":" + TOKEN_WHITESPACE@11..12 " " + NODE_LITERAL@12..13 + TOKEN_INTEGER@12..13 "1" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_right.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_right.nix new file mode 100644 index 0000000..eca392c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_bind_right.nix @@ -0,0 +1 @@ +{} @ outer: 1 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default.expect new file mode 100644 index 0000000..fbd1b53 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default.expect @@ -0,0 +1,27 @@ +NODE_ROOT@0..23 + NODE_LAMBDA@0..23 + NODE_PATTERN@0..20 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..2 " " + NODE_PAT_ENTRY@2..3 + NODE_IDENT@2..3 + TOKEN_IDENT@2..3 "a" + TOKEN_COMMA@3..4 "," + TOKEN_WHITESPACE@4..5 " " + NODE_PAT_ENTRY@5..18 + NODE_IDENT@5..6 + TOKEN_IDENT@5..6 "b" + TOKEN_WHITESPACE@6..7 " " + TOKEN_QUESTION@7..8 "?" + TOKEN_WHITESPACE@8..9 " " + NODE_STRING@9..18 + TOKEN_STRING_START@9..10 "\"" + TOKEN_STRING_CONTENT@10..17 "default" + TOKEN_STRING_END@17..18 "\"" + TOKEN_WHITESPACE@18..19 " " + TOKEN_R_BRACE@19..20 "}" + TOKEN_COLON@20..21 ":" + TOKEN_WHITESPACE@21..22 " " + NODE_IDENT@22..23 + TOKEN_IDENT@22..23 "a" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default.nix new file mode 100644 index 0000000..ccc5438 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default.nix @@ -0,0 +1 @@ +{ a, b ? "default" }: a diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_attrset.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_attrset.expect new file mode 100644 index 0000000..4968e0e --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_attrset.expect @@ -0,0 +1,16 @@ +NODE_ROOT@0..8 + NODE_LAMBDA@0..8 + NODE_PATTERN@0..6 + TOKEN_L_BRACE@0..1 "{" + NODE_PAT_ENTRY@1..5 + NODE_IDENT@1..2 + TOKEN_IDENT@1..2 "a" + TOKEN_QUESTION@2..3 "?" + NODE_ATTR_SET@3..5 + TOKEN_L_BRACE@3..4 "{" + TOKEN_R_BRACE@4..5 "}" + TOKEN_R_BRACE@5..6 "}" + TOKEN_COLON@6..7 ":" + NODE_IDENT@7..8 + TOKEN_IDENT@7..8 "a" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_attrset.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_attrset.nix new file mode 100644 index 0000000..242a07d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_attrset.nix @@ -0,0 +1 @@ +{a?{}}:a diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_ellipsis.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_ellipsis.expect new file mode 100644 index 0000000..8635432 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_ellipsis.expect @@ -0,0 +1,30 @@ +NODE_ROOT@0..28 + NODE_LAMBDA@0..28 + NODE_PATTERN@0..25 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..2 " " + NODE_PAT_ENTRY@2..3 + NODE_IDENT@2..3 + TOKEN_IDENT@2..3 "a" + TOKEN_COMMA@3..4 "," + TOKEN_WHITESPACE@4..5 " " + NODE_PAT_ENTRY@5..18 + NODE_IDENT@5..6 + TOKEN_IDENT@5..6 "b" + TOKEN_WHITESPACE@6..7 " " + TOKEN_QUESTION@7..8 "?" + TOKEN_WHITESPACE@8..9 " " + NODE_STRING@9..18 + TOKEN_STRING_START@9..10 "\"" + TOKEN_STRING_CONTENT@10..17 "default" + TOKEN_STRING_END@17..18 "\"" + TOKEN_COMMA@18..19 "," + TOKEN_WHITESPACE@19..20 " " + TOKEN_ELLIPSIS@20..23 "..." + TOKEN_WHITESPACE@23..24 " " + TOKEN_R_BRACE@24..25 "}" + TOKEN_COLON@25..26 ":" + TOKEN_WHITESPACE@26..27 " " + NODE_IDENT@27..28 + TOKEN_IDENT@27..28 "a" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_ellipsis.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_ellipsis.nix new file mode 100644 index 0000000..68006bc --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_default_ellipsis.nix @@ -0,0 +1 @@ +{ a, b ? "default", ... }: a diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_ellipsis.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_ellipsis.expect new file mode 100644 index 0000000..40845fe --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_ellipsis.expect @@ -0,0 +1,13 @@ +NODE_ROOT@0..10 + NODE_LAMBDA@0..10 + NODE_PATTERN@0..7 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..2 " " + TOKEN_ELLIPSIS@2..5 "..." + TOKEN_WHITESPACE@5..6 " " + TOKEN_R_BRACE@6..7 "}" + TOKEN_COLON@7..8 ":" + TOKEN_WHITESPACE@8..9 " " + NODE_LITERAL@9..10 + TOKEN_INTEGER@9..10 "1" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_ellipsis.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_ellipsis.nix new file mode 100644 index 0000000..8938015 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_ellipsis.nix @@ -0,0 +1 @@ +{ ... }: 1 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_trailing_comma.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_trailing_comma.expect new file mode 100644 index 0000000..a87136d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_trailing_comma.expect @@ -0,0 +1,13 @@ +NODE_ROOT@0..6 + NODE_LAMBDA@0..6 + NODE_PATTERN@0..4 + TOKEN_L_BRACE@0..1 "{" + NODE_PAT_ENTRY@1..2 + NODE_IDENT@1..2 + TOKEN_IDENT@1..2 "a" + TOKEN_COMMA@2..3 "," + TOKEN_R_BRACE@3..4 "}" + TOKEN_COLON@4..5 ":" + NODE_IDENT@5..6 + TOKEN_IDENT@5..6 "a" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_trailing_comma.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_trailing_comma.nix new file mode 100644 index 0000000..d9e2dad --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pattern_trailing_comma.nix @@ -0,0 +1 @@ +{a,}:a diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left.expect new file mode 100644 index 0000000..236be39 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left.expect @@ -0,0 +1,15 @@ +NODE_ROOT@0..22 + NODE_BIN_OP@0..22 + NODE_SELECT@0..17 + NODE_IDENT@0..8 + TOKEN_IDENT@0..8 "builtins" + TOKEN_DOT@8..9 "." + NODE_ATTRPATH@9..17 + NODE_IDENT@9..17 + TOKEN_IDENT@9..17 "toString" + TOKEN_WHITESPACE@17..18 " " + TOKEN_PIPE_LEFT@18..20 "<|" + TOKEN_WHITESPACE@20..21 " " + NODE_LITERAL@21..22 + TOKEN_INTEGER@21..22 "1" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left.nix new file mode 100644 index 0000000..ce3b8e1 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left.nix @@ -0,0 +1 @@ +builtins.toString <| 1 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_assoc.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_assoc.expect new file mode 100644 index 0000000..f58e2e4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_assoc.expect @@ -0,0 +1,21 @@ +NODE_ROOT@0..29 + NODE_BIN_OP@0..29 + NODE_IDENT@0..3 + TOKEN_IDENT@0..3 "foo" + TOKEN_WHITESPACE@3..4 " " + TOKEN_PIPE_LEFT@4..6 "<|" + TOKEN_WHITESPACE@6..7 " " + NODE_BIN_OP@7..29 + NODE_SELECT@7..24 + NODE_IDENT@7..15 + TOKEN_IDENT@7..15 "builtins" + TOKEN_DOT@15..16 "." + NODE_ATTRPATH@16..24 + NODE_IDENT@16..24 + TOKEN_IDENT@16..24 "toString" + TOKEN_WHITESPACE@24..25 " " + TOKEN_PIPE_LEFT@25..27 "<|" + TOKEN_WHITESPACE@27..28 " " + NODE_LITERAL@28..29 + TOKEN_INTEGER@28..29 "1" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_assoc.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_assoc.nix new file mode 100644 index 0000000..c0d111c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_assoc.nix @@ -0,0 +1 @@ +foo <| builtins.toString <| 1 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_math.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_math.expect new file mode 100644 index 0000000..3dbf0bb --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_math.expect @@ -0,0 +1,21 @@ +NODE_ROOT@0..26 + NODE_BIN_OP@0..26 + NODE_SELECT@0..17 + NODE_IDENT@0..8 + TOKEN_IDENT@0..8 "builtins" + TOKEN_DOT@8..9 "." + NODE_ATTRPATH@9..17 + NODE_IDENT@9..17 + TOKEN_IDENT@9..17 "toString" + TOKEN_WHITESPACE@17..18 " " + TOKEN_PIPE_LEFT@18..20 "<|" + TOKEN_WHITESPACE@20..21 " " + NODE_BIN_OP@21..26 + NODE_LITERAL@21..22 + TOKEN_INTEGER@21..22 "1" + TOKEN_WHITESPACE@22..23 " " + TOKEN_ADD@23..24 "+" + TOKEN_WHITESPACE@24..25 " " + NODE_LITERAL@25..26 + TOKEN_INTEGER@25..26 "1" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_math.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_math.nix new file mode 100644 index 0000000..62872ee --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_left_math.nix @@ -0,0 +1 @@ +builtins.toString <| 1 + 1 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed.expect new file mode 100644 index 0000000..7462509 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed.expect @@ -0,0 +1,21 @@ +NODE_ROOT@0..29 + NODE_BIN_OP@0..29 + NODE_SELECT@0..17 + NODE_IDENT@0..8 + TOKEN_IDENT@0..8 "builtins" + TOKEN_DOT@8..9 "." + NODE_ATTRPATH@9..17 + NODE_IDENT@9..17 + TOKEN_IDENT@9..17 "toString" + TOKEN_WHITESPACE@17..18 " " + TOKEN_PIPE_LEFT@18..20 "<|" + TOKEN_WHITESPACE@20..21 " " + NODE_BIN_OP@21..29 + NODE_LITERAL@21..22 + TOKEN_INTEGER@21..22 "1" + TOKEN_WHITESPACE@22..23 " " + TOKEN_PIPE_RIGHT@23..25 "|>" + TOKEN_WHITESPACE@25..26 " " + NODE_IDENT@26..29 + TOKEN_IDENT@26..29 "foo" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed.nix new file mode 100644 index 0000000..260f2f8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed.nix @@ -0,0 +1 @@ +builtins.toString <| 1 |> foo diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed_math.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed_math.expect new file mode 100644 index 0000000..69bd187 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed_math.expect @@ -0,0 +1,27 @@ +NODE_ROOT@0..33 + NODE_BIN_OP@0..33 + NODE_SELECT@0..17 + NODE_IDENT@0..8 + TOKEN_IDENT@0..8 "builtins" + TOKEN_DOT@8..9 "." + NODE_ATTRPATH@9..17 + NODE_IDENT@9..17 + TOKEN_IDENT@9..17 "toString" + TOKEN_WHITESPACE@17..18 " " + TOKEN_PIPE_LEFT@18..20 "<|" + TOKEN_WHITESPACE@20..21 " " + NODE_BIN_OP@21..33 + NODE_BIN_OP@21..26 + NODE_LITERAL@21..22 + TOKEN_INTEGER@21..22 "1" + TOKEN_WHITESPACE@22..23 " " + TOKEN_ADD@23..24 "+" + TOKEN_WHITESPACE@24..25 " " + NODE_LITERAL@25..26 + TOKEN_INTEGER@25..26 "1" + TOKEN_WHITESPACE@26..27 " " + TOKEN_PIPE_RIGHT@27..29 "|>" + TOKEN_WHITESPACE@29..30 " " + NODE_IDENT@30..33 + TOKEN_IDENT@30..33 "foo" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed_math.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed_math.nix new file mode 100644 index 0000000..880807d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_mixed_math.nix @@ -0,0 +1 @@ +builtins.toString <| 1 + 1 |> foo diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right.expect new file mode 100644 index 0000000..7d35f6e --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right.expect @@ -0,0 +1,15 @@ +NODE_ROOT@0..22 + NODE_BIN_OP@0..22 + NODE_LITERAL@0..1 + TOKEN_INTEGER@0..1 "1" + TOKEN_WHITESPACE@1..2 " " + TOKEN_PIPE_RIGHT@2..4 "|>" + TOKEN_WHITESPACE@4..5 " " + NODE_SELECT@5..22 + NODE_IDENT@5..13 + TOKEN_IDENT@5..13 "builtins" + TOKEN_DOT@13..14 "." + NODE_ATTRPATH@14..22 + NODE_IDENT@14..22 + TOKEN_IDENT@14..22 "toString" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right.nix new file mode 100644 index 0000000..5666662 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right.nix @@ -0,0 +1 @@ +1 |> builtins.toString diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_assoc.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_assoc.expect new file mode 100644 index 0000000..c279197 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_assoc.expect @@ -0,0 +1,21 @@ +NODE_ROOT@0..29 + NODE_BIN_OP@0..29 + NODE_BIN_OP@0..22 + NODE_LITERAL@0..1 + TOKEN_INTEGER@0..1 "1" + TOKEN_WHITESPACE@1..2 " " + TOKEN_PIPE_RIGHT@2..4 "|>" + TOKEN_WHITESPACE@4..5 " " + NODE_SELECT@5..22 + NODE_IDENT@5..13 + TOKEN_IDENT@5..13 "builtins" + TOKEN_DOT@13..14 "." + NODE_ATTRPATH@14..22 + NODE_IDENT@14..22 + TOKEN_IDENT@14..22 "toString" + TOKEN_WHITESPACE@22..23 " " + TOKEN_PIPE_RIGHT@23..25 "|>" + TOKEN_WHITESPACE@25..26 " " + NODE_IDENT@26..29 + TOKEN_IDENT@26..29 "foo" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_assoc.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_assoc.nix new file mode 100644 index 0000000..bbb2e8f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_assoc.nix @@ -0,0 +1 @@ +1 |> builtins.toString |> foo diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_math.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_math.expect new file mode 100644 index 0000000..a41e870 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_math.expect @@ -0,0 +1,21 @@ +NODE_ROOT@0..26 + NODE_BIN_OP@0..26 + NODE_BIN_OP@0..5 + NODE_LITERAL@0..1 + TOKEN_INTEGER@0..1 "1" + TOKEN_WHITESPACE@1..2 " " + TOKEN_ADD@2..3 "+" + TOKEN_WHITESPACE@3..4 " " + NODE_LITERAL@4..5 + TOKEN_INTEGER@4..5 "1" + TOKEN_WHITESPACE@5..6 " " + TOKEN_PIPE_RIGHT@6..8 "|>" + TOKEN_WHITESPACE@8..9 " " + NODE_SELECT@9..26 + NODE_IDENT@9..17 + TOKEN_IDENT@9..17 "builtins" + TOKEN_DOT@17..18 "." + NODE_ATTRPATH@18..26 + NODE_IDENT@18..26 + TOKEN_IDENT@18..26 "toString" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_math.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_math.nix new file mode 100644 index 0000000..9245e7d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/pipe_right_math.nix @@ -0,0 +1 @@ +1 + 1 |> builtins.toString diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/select_default.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_default.expect new file mode 100644 index 0000000..6520fea --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_default.expect @@ -0,0 +1,23 @@ +NODE_ROOT@0..14 + NODE_BIN_OP@0..14 + NODE_SELECT@0..10 + NODE_IDENT@0..1 + TOKEN_IDENT@0..1 "a" + TOKEN_DOT@1..2 "." + NODE_ATTRPATH@2..5 + NODE_IDENT@2..3 + TOKEN_IDENT@2..3 "b" + TOKEN_DOT@3..4 "." + NODE_IDENT@4..5 + TOKEN_IDENT@4..5 "c" + TOKEN_WHITESPACE@5..6 " " + TOKEN_OR@6..8 "or" + TOKEN_WHITESPACE@8..9 " " + NODE_LITERAL@9..10 + TOKEN_INTEGER@9..10 "1" + TOKEN_WHITESPACE@10..11 " " + TOKEN_ADD@11..12 "+" + TOKEN_WHITESPACE@12..13 " " + NODE_LITERAL@13..14 + TOKEN_INTEGER@13..14 "1" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/select_default.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_default.nix new file mode 100644 index 0000000..fbfbdcf --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_default.nix @@ -0,0 +1 @@ +a.b.c or 1 + 1 diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/select_ident.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_ident.expect new file mode 100644 index 0000000..d157a80 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_ident.expect @@ -0,0 +1,12 @@ +NODE_ROOT@0..5 + NODE_SELECT@0..5 + NODE_IDENT@0..1 + TOKEN_IDENT@0..1 "a" + TOKEN_DOT@1..2 "." + NODE_ATTRPATH@2..5 + NODE_IDENT@2..3 + TOKEN_IDENT@2..3 "b" + TOKEN_DOT@3..4 "." + NODE_IDENT@4..5 + TOKEN_IDENT@4..5 "c" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/select_ident.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_ident.nix new file mode 100644 index 0000000..706eeff --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_ident.nix @@ -0,0 +1 @@ +a.b.c diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/select_string_dynamic.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_string_dynamic.expect new file mode 100644 index 0000000..509a7a5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_string_dynamic.expect @@ -0,0 +1,26 @@ +NODE_ROOT@0..33 + NODE_SELECT@0..33 + NODE_IDENT@0..4 + TOKEN_IDENT@0..4 "test" + TOKEN_DOT@4..5 "." + NODE_ATTRPATH@5..33 + NODE_STRING@5..20 + TOKEN_STRING_START@5..6 "\"" + TOKEN_STRING_CONTENT@6..19 "invalid ident" + TOKEN_STRING_END@19..20 "\"" + TOKEN_DOT@20..21 "." + NODE_STRING@21..28 + TOKEN_STRING_START@21..22 "\"" + NODE_INTERPOL@22..27 + TOKEN_INTERPOL_START@22..24 "${" + NODE_IDENT@24..26 + TOKEN_IDENT@24..26 "hi" + TOKEN_INTERPOL_END@26..27 "}" + TOKEN_STRING_END@27..28 "\"" + TOKEN_DOT@28..29 "." + NODE_DYNAMIC@29..33 + TOKEN_INTERPOL_START@29..31 "${" + NODE_IDENT@31..32 + TOKEN_IDENT@31..32 "a" + TOKEN_INTERPOL_END@32..33 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/select_string_dynamic.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_string_dynamic.nix new file mode 100644 index 0000000..1ae38a5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/select_string_dynamic.nix @@ -0,0 +1 @@ +test."invalid ident"."${hi}".${a} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/string.expect new file mode 100644 index 0000000..a442606 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string.expect @@ -0,0 +1,43 @@ +NODE_ROOT@0..137 + NODE_ATTR_SET@0..137 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..21 + NODE_ATTRPATH@4..10 + NODE_IDENT@4..10 + TOKEN_IDENT@4..10 "simple" + TOKEN_WHITESPACE@10..11 " " + TOKEN_ASSIGN@11..12 "=" + TOKEN_WHITESPACE@12..13 " " + NODE_STRING@13..20 + TOKEN_STRING_START@13..14 "\"" + TOKEN_STRING_CONTENT@14..19 "hello" + TOKEN_STRING_END@19..20 "\"" + TOKEN_SEMICOLON@20..21 ";" + TOKEN_WHITESPACE@21..24 "\n " + NODE_ATTRPATH_VALUE@24..63 + NODE_ATTRPATH@24..32 + NODE_IDENT@24..32 + TOKEN_IDENT@24..32 "indented" + TOKEN_WHITESPACE@32..33 " " + TOKEN_ASSIGN@33..34 "=" + TOKEN_WHITESPACE@34..35 " " + NODE_STRING@35..62 + TOKEN_STRING_START@35..37 "''" + TOKEN_STRING_CONTENT@37..60 "\n hello\n world\n " + TOKEN_STRING_END@60..62 "''" + TOKEN_SEMICOLON@62..63 ";" + TOKEN_WHITESPACE@63..66 "\n " + NODE_ATTRPATH_VALUE@66..135 + NODE_ATTRPATH@66..101 + NODE_IDENT@66..101 + TOKEN_IDENT@66..101 "uri_is_also_a_string_ ..." + TOKEN_WHITESPACE@101..102 " " + TOKEN_ASSIGN@102..103 "=" + TOKEN_WHITESPACE@103..104 " " + NODE_LITERAL@104..134 + TOKEN_URI@104..134 "http://example.org/fo ..." + TOKEN_SEMICOLON@134..135 ";" + TOKEN_WHITESPACE@135..136 "\n" + TOKEN_R_BRACE@136..137 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/string.nix new file mode 100644 index 0000000..4c618db --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string.nix @@ -0,0 +1,8 @@ +{ + simple = "hello"; + indented = '' + hello + world + ''; + uri_is_also_a_string_how_convenient = http://example.org/foo.tar.bz2; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_complex_url.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_complex_url.expect new file mode 100644 index 0000000..731efd8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_complex_url.expect @@ -0,0 +1,17 @@ +NODE_ROOT@0..99 + NODE_ATTR_SET@0..99 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..97 + NODE_ATTRPATH@4..24 + NODE_IDENT@4..24 + TOKEN_IDENT@4..24 "more_complicated_url" + TOKEN_WHITESPACE@24..25 " " + TOKEN_ASSIGN@25..26 "=" + TOKEN_WHITESPACE@26..31 "\n " + NODE_LITERAL@31..96 + TOKEN_URI@31..96 "http://c758482.r82.cf ..." + TOKEN_SEMICOLON@96..97 ";" + TOKEN_WHITESPACE@97..98 "\n" + TOKEN_R_BRACE@98..99 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_complex_url.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_complex_url.nix new file mode 100644 index 0000000..5daa9c8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_complex_url.nix @@ -0,0 +1,4 @@ +{ + more_complicated_url = + http://c758482.r82.cf2.rackcdn.com/Sublime%20Text%202.0.2.tar.bz2; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_escape_issue175.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_escape_issue175.expect new file mode 100644 index 0000000..4a17afb --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_escape_issue175.expect @@ -0,0 +1,6 @@ +NODE_ROOT@0..14 + NODE_STRING@0..14 + TOKEN_STRING_START@0..2 "''" + TOKEN_STRING_CONTENT@2..12 "\n''\\'''${\n" + TOKEN_STRING_END@12..14 "''" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_escape_issue175.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_escape_issue175.nix new file mode 100644 index 0000000..6a09ea2 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_escape_issue175.nix @@ -0,0 +1,3 @@ +'' +''\'''${ +'' diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_ident.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_ident.expect new file mode 100644 index 0000000..17a02e5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_ident.expect @@ -0,0 +1,18 @@ +NODE_ROOT@0..21 + TOKEN_WHITESPACE@0..1 " " + NODE_STRING@1..20 + TOKEN_STRING_START@1..2 "\"" + NODE_INTERPOL@2..10 + TOKEN_INTERPOL_START@2..4 "${" + NODE_IDENT@4..9 + TOKEN_IDENT@4..9 "hello" + TOKEN_INTERPOL_END@9..10 "}" + TOKEN_STRING_CONTENT@10..11 " " + NODE_INTERPOL@11..19 + TOKEN_INTERPOL_START@11..13 "${" + NODE_IDENT@13..18 + TOKEN_IDENT@13..18 "world" + TOKEN_INTERPOL_END@18..19 "}" + TOKEN_STRING_END@19..20 "\"" + TOKEN_WHITESPACE@20..21 " " + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_ident.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_ident.nix new file mode 100644 index 0000000..13e8028 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_ident.nix @@ -0,0 +1 @@ + "${hello} ${world}" diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_nested.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_nested.expect new file mode 100644 index 0000000..d837955 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_nested.expect @@ -0,0 +1,18 @@ +NODE_ROOT@0..17 + TOKEN_WHITESPACE@0..1 " " + NODE_STRING@1..16 + TOKEN_STRING_START@1..3 "''" + NODE_INTERPOL@3..14 + TOKEN_INTERPOL_START@3..5 "${" + NODE_STRING@5..13 + TOKEN_STRING_START@5..6 "\"" + NODE_INTERPOL@6..12 + TOKEN_INTERPOL_START@6..8 "${" + NODE_IDENT@8..11 + TOKEN_IDENT@8..11 "var" + TOKEN_INTERPOL_END@11..12 "}" + TOKEN_STRING_END@12..13 "\"" + TOKEN_INTERPOL_END@13..14 "}" + TOKEN_STRING_END@14..16 "''" + TOKEN_WHITESPACE@16..17 " " + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_nested.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_nested.nix new file mode 100644 index 0000000..97a1d95 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_nested.nix @@ -0,0 +1 @@ + ''${"${var}"}'' diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_select.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_select.expect new file mode 100644 index 0000000..6973dcc --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_select.expect @@ -0,0 +1,36 @@ +NODE_ROOT@0..43 + TOKEN_WHITESPACE@0..1 " " + NODE_STRING@1..42 + TOKEN_STRING_START@1..2 "\"" + TOKEN_STRING_CONTENT@2..9 "Hello, " + NODE_INTERPOL@9..40 + TOKEN_INTERPOL_START@9..11 "${" + TOKEN_WHITESPACE@11..12 " " + NODE_SELECT@12..38 + NODE_ATTR_SET@12..32 + TOKEN_L_BRACE@12..13 "{" + TOKEN_WHITESPACE@13..14 " " + NODE_ATTRPATH_VALUE@14..30 + NODE_ATTRPATH@14..19 + NODE_IDENT@14..19 + TOKEN_IDENT@14..19 "world" + TOKEN_WHITESPACE@19..20 " " + TOKEN_ASSIGN@20..21 "=" + TOKEN_WHITESPACE@21..22 " " + NODE_STRING@22..29 + TOKEN_STRING_START@22..23 "\"" + TOKEN_STRING_CONTENT@23..28 "World" + TOKEN_STRING_END@28..29 "\"" + TOKEN_SEMICOLON@29..30 ";" + TOKEN_WHITESPACE@30..31 " " + TOKEN_R_BRACE@31..32 "}" + TOKEN_DOT@32..33 "." + NODE_ATTRPATH@33..38 + NODE_IDENT@33..38 + TOKEN_IDENT@33..38 "world" + TOKEN_WHITESPACE@38..39 " " + TOKEN_INTERPOL_END@39..40 "}" + TOKEN_STRING_CONTENT@40..41 "!" + TOKEN_STRING_END@41..42 "\"" + TOKEN_WHITESPACE@42..43 " " + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_select.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_select.nix new file mode 100644 index 0000000..eb44dd7 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/string_interp_select.nix @@ -0,0 +1 @@ + "Hello, ${ { world = "World"; }.world }!" diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/trivia.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/trivia.expect new file mode 100644 index 0000000..2f7f63f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/trivia.expect @@ -0,0 +1,84 @@ +NODE_ROOT@0..229 + NODE_ATTR_SET@0..197 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..67 + NODE_ATTRPATH@4..7 + NODE_IDENT@4..7 + TOKEN_IDENT@4..7 "add" + TOKEN_WHITESPACE@7..8 " " + TOKEN_ASSIGN@8..9 "=" + TOKEN_WHITESPACE@9..10 " " + TOKEN_COMMENT@10..31 "/* the first value */" + TOKEN_WHITESPACE@31..32 " " + NODE_LAMBDA@32..66 + NODE_IDENT_PARAM@32..33 + NODE_IDENT@32..33 + TOKEN_IDENT@32..33 "x" + TOKEN_COLON@33..34 ":" + TOKEN_WHITESPACE@34..35 " " + TOKEN_COMMENT@35..57 "/* the second value */" + TOKEN_WHITESPACE@57..58 " " + NODE_LAMBDA@58..66 + NODE_IDENT_PARAM@58..59 + NODE_IDENT@58..59 + TOKEN_IDENT@58..59 "y" + TOKEN_COLON@59..60 ":" + TOKEN_WHITESPACE@60..61 " " + NODE_BIN_OP@61..66 + NODE_IDENT@61..62 + TOKEN_IDENT@61..62 "x" + TOKEN_WHITESPACE@62..63 " " + TOKEN_ADD@63..64 "+" + TOKEN_WHITESPACE@64..65 " " + NODE_IDENT@65..66 + TOKEN_IDENT@65..66 "y" + TOKEN_SEMICOLON@66..67 ";" + TOKEN_WHITESPACE@67..70 "\n " + NODE_ATTRPATH_VALUE@70..106 + NODE_ATTRPATH@70..76 + NODE_IDENT@70..76 + TOKEN_IDENT@70..76 "string" + TOKEN_WHITESPACE@76..77 " " + TOKEN_ASSIGN@77..78 "=" + TOKEN_WHITESPACE@78..79 " " + TOKEN_COMMENT@79..100 "/* meaning of life */" + TOKEN_WHITESPACE@100..101 " " + NODE_STRING@101..105 + TOKEN_STRING_START@101..102 "\"" + TOKEN_STRING_CONTENT@102..104 "42" + TOKEN_STRING_END@104..105 "\"" + TOKEN_SEMICOLON@105..106 ";" + TOKEN_WHITESPACE@106..111 "\n " + NODE_ATTRPATH_VALUE@111..126 + NODE_ATTRPATH@111..113 + NODE_IDENT@111..113 + TOKEN_IDENT@111..113 "hi" + TOKEN_WHITESPACE@113..114 " " + TOKEN_ASSIGN@114..115 "=" + TOKEN_WHITESPACE@115..116 " " + NODE_LITERAL@116..125 + TOKEN_FLOAT@116..125 "3.0000000" + TOKEN_SEMICOLON@125..126 ";" + TOKEN_WHITESPACE@126..128 "\n " + TOKEN_COMMENT@128..161 "# Store my password i ..." + TOKEN_WHITESPACE@161..168 "\n " + NODE_ATTRPATH_VALUE@168..195 + NODE_ATTRPATH@168..176 + NODE_IDENT@168..176 + TOKEN_IDENT@168..176 "password" + TOKEN_WHITESPACE@176..178 " " + TOKEN_ASSIGN@178..179 "=" + TOKEN_WHITESPACE@179..185 " " + NODE_STRING@185..194 + TOKEN_STRING_START@185..186 "\"" + TOKEN_STRING_CONTENT@186..193 "hunter2" + TOKEN_STRING_END@193..194 "\"" + TOKEN_SEMICOLON@194..195 ";" + TOKEN_WHITESPACE@195..196 "\n" + TOKEN_R_BRACE@196..197 "}" + TOKEN_WHITESPACE@197..201 "\n " + TOKEN_COMMENT@201..211 "# trailing" + TOKEN_WHITESPACE@211..219 "\n " + TOKEN_COMMENT@219..229 "# comments" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/trivia.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/trivia.nix new file mode 100644 index 0000000..74f3268 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/trivia.nix @@ -0,0 +1,9 @@ +{ + add = /* the first value */ x: /* the second value */ y: x + y; + string = /* meaning of life */ "42"; + hi = 3.0000000; + # Store my password in plain text + password = "hunter2"; +} + # trailing + # comments diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/uri_various.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/uri_various.expect new file mode 100644 index 0000000..525c93f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/uri_various.expect @@ -0,0 +1,96 @@ +error: unexpected TOKEN_ASSIGN at 361..388, wanted any of [TOKEN_SEMICOLON] +NODE_ROOT@0..391 + NODE_ATTR_SET@0..391 + TOKEN_L_BRACE@0..1 "{" + TOKEN_WHITESPACE@1..4 "\n " + NODE_ATTRPATH_VALUE@4..30 + NODE_ATTRPATH@4..8 + NODE_IDENT@4..8 + TOKEN_IDENT@4..8 "http" + TOKEN_WHITESPACE@8..9 " " + TOKEN_ASSIGN@9..10 "=" + TOKEN_WHITESPACE@10..11 " " + NODE_LITERAL@11..29 + TOKEN_URI@11..29 "http://example.com" + TOKEN_SEMICOLON@29..30 ";" + TOKEN_WHITESPACE@30..33 "\n " + NODE_ATTRPATH_VALUE@33..74 + NODE_ATTRPATH@33..38 + NODE_IDENT@33..38 + TOKEN_IDENT@33..38 "https" + TOKEN_WHITESPACE@38..39 " " + TOKEN_ASSIGN@39..40 "=" + TOKEN_WHITESPACE@40..41 " " + NODE_LITERAL@41..73 + TOKEN_URI@41..73 "https://github.com/Ni ..." + TOKEN_SEMICOLON@73..74 ";" + TOKEN_WHITESPACE@74..77 "\n " + NODE_ATTRPATH_VALUE@77..123 + NODE_ATTRPATH@77..80 + NODE_IDENT@77..80 + TOKEN_IDENT@77..80 "git" + TOKEN_WHITESPACE@80..81 " " + TOKEN_ASSIGN@81..82 "=" + TOKEN_WHITESPACE@82..83 " " + NODE_LITERAL@83..122 + TOKEN_URI@83..122 "git+ssh://git@github. ..." + TOKEN_SEMICOLON@122..123 ";" + TOKEN_WHITESPACE@123..126 "\n " + NODE_ATTRPATH_VALUE@126..164 + NODE_ATTRPATH@126..130 + NODE_IDENT@126..130 + TOKEN_IDENT@126..130 "file" + TOKEN_WHITESPACE@130..131 " " + TOKEN_ASSIGN@131..132 "=" + TOKEN_WHITESPACE@132..133 " " + NODE_LITERAL@133..163 + TOKEN_URI@133..163 "file:///home/user/doc ..." + TOKEN_SEMICOLON@163..164 ";" + TOKEN_WHITESPACE@164..167 "\n " + NODE_ATTRPATH_VALUE@167..211 + NODE_ATTRPATH@167..170 + NODE_IDENT@167..170 + TOKEN_IDENT@167..170 "ftp" + TOKEN_WHITESPACE@170..171 " " + TOKEN_ASSIGN@171..172 "=" + TOKEN_WHITESPACE@172..173 " " + NODE_LITERAL@173..210 + TOKEN_URI@173..210 "ftp://ftp.example.com ..." + TOKEN_SEMICOLON@210..211 ";" + TOKEN_WHITESPACE@211..217 "\n \n " + TOKEN_COMMENT@217..247 "# URIs with special c ..." + TOKEN_WHITESPACE@247..250 "\n " + NODE_ATTRPATH_VALUE@250..298 + NODE_ATTRPATH@250..259 + NODE_IDENT@250..259 + TOKEN_IDENT@250..259 "withQuery" + TOKEN_WHITESPACE@259..260 " " + TOKEN_ASSIGN@260..261 "=" + TOKEN_WHITESPACE@261..262 " " + NODE_LITERAL@262..297 + TOKEN_URI@262..297 "https://example.com?f ..." + TOKEN_SEMICOLON@297..298 ";" + TOKEN_WHITESPACE@298..301 "\n " + NODE_ATTRPATH_VALUE@301..389 + NODE_ATTRPATH@301..313 + NODE_IDENT@301..313 + TOKEN_IDENT@301..313 "withFragment" + TOKEN_WHITESPACE@313..314 " " + TOKEN_ASSIGN@314..315 "=" + TOKEN_WHITESPACE@315..316 " " + NODE_APPLY@316..360 + NODE_LITERAL@316..340 + TOKEN_URI@316..340 "https://example.com/page" + TOKEN_COMMENT@340..349 "#section;" + TOKEN_WHITESPACE@349..352 "\n " + NODE_IDENT@352..360 + TOKEN_IDENT@352..360 "withPort" + TOKEN_WHITESPACE@360..361 " " + NODE_ERROR@361..388 + TOKEN_ASSIGN@361..362 "=" + TOKEN_WHITESPACE@362..363 " " + TOKEN_URI@363..388 "http://localhost:8080 ..." + TOKEN_SEMICOLON@388..389 ";" + TOKEN_WHITESPACE@389..390 "\n" + TOKEN_R_BRACE@390..391 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/uri_various.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/uri_various.nix new file mode 100644 index 0000000..345b1a7 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/uri_various.nix @@ -0,0 +1,12 @@ +{ + http = http://example.com; + https = https://github.com/NixOS/nixpkgs; + git = git+ssh://git@github.com/owner/repo.git; + file = file:///home/user/document.pdf; + ftp = ftp://ftp.example.com/pub/file.tar.gz; + + # URIs with special characters + withQuery = https://example.com?foo=bar&baz=qux; + withFragment = https://example.com/page#section; + withPort = http://localhost:8080/api; +} \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/with-import-let-in.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/with-import-let-in.expect new file mode 100644 index 0000000..0d90fcc --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/with-import-let-in.expect @@ -0,0 +1,93 @@ +NODE_ROOT@0..150 + NODE_WITH@0..150 + TOKEN_WITH@0..4 "with" + TOKEN_WHITESPACE@4..5 " " + NODE_APPLY@5..28 + NODE_IDENT@5..11 + TOKEN_IDENT@5..11 "import" + TOKEN_WHITESPACE@11..12 " " + NODE_PATH_REL@12..28 + TOKEN_PATH_REL@12..28 "./simple-set.nix" + TOKEN_SEMICOLON@28..29 ";" + TOKEN_WHITESPACE@29..31 "\n\n" + NODE_LET_IN@31..150 + TOKEN_LET@31..34 "let" + TOKEN_WHITESPACE@34..37 "\n " + NODE_ATTRPATH_VALUE@37..47 + NODE_ATTRPATH@37..38 + NODE_IDENT@37..38 + TOKEN_IDENT@37..38 "a" + TOKEN_WHITESPACE@38..39 " " + TOKEN_ASSIGN@39..40 "=" + TOKEN_WHITESPACE@40..41 " " + NODE_BIN_OP@41..46 + NODE_LITERAL@41..42 + TOKEN_INTEGER@41..42 "4" + TOKEN_WHITESPACE@42..43 " " + TOKEN_ADD@43..44 "+" + TOKEN_WHITESPACE@44..45 " " + NODE_LITERAL@45..46 + TOKEN_INTEGER@45..46 "2" + TOKEN_SEMICOLON@46..47 ";" + TOKEN_WHITESPACE@47..48 "\n" + TOKEN_IN@48..50 "in" + TOKEN_WHITESPACE@50..51 " " + NODE_ATTR_SET@51..150 + TOKEN_L_BRACE@51..52 "{" + TOKEN_WHITESPACE@52..55 "\n " + NODE_ATTRPATH_VALUE@55..65 + NODE_ATTRPATH@55..56 + NODE_IDENT@55..56 + TOKEN_IDENT@55..56 "b" + TOKEN_WHITESPACE@56..57 " " + TOKEN_ASSIGN@57..58 "=" + TOKEN_WHITESPACE@58..59 " " + NODE_BIN_OP@59..64 + NODE_IDENT@59..60 + TOKEN_IDENT@59..60 "a" + TOKEN_WHITESPACE@60..61 " " + TOKEN_ADD@61..62 "+" + TOKEN_WHITESPACE@62..63 " " + NODE_LITERAL@63..64 + TOKEN_INTEGER@63..64 "2" + TOKEN_SEMICOLON@64..65 ";" + TOKEN_WHITESPACE@65..69 "\n\n " + NODE_ATTRPATH_VALUE@69..148 + NODE_ATTRPATH@69..75 + NODE_IDENT@69..75 + TOKEN_IDENT@69..75 "legacy" + TOKEN_WHITESPACE@75..76 " " + TOKEN_ASSIGN@76..77 "=" + TOKEN_WHITESPACE@77..78 " " + NODE_LEGACY_LET@78..147 + TOKEN_LET@78..81 "let" + TOKEN_WHITESPACE@81..82 " " + TOKEN_L_BRACE@82..83 "{" + TOKEN_WHITESPACE@83..88 "\n " + NODE_ATTRPATH_VALUE@88..113 + NODE_ATTRPATH@88..105 + NODE_IDENT@88..105 + TOKEN_IDENT@88..105 "this_syntax_sucks" + TOKEN_WHITESPACE@105..106 " " + TOKEN_ASSIGN@106..107 "=" + TOKEN_WHITESPACE@107..108 " " + NODE_IDENT@108..112 + TOKEN_IDENT@108..112 "true" + TOKEN_SEMICOLON@112..113 ";" + TOKEN_WHITESPACE@113..118 "\n " + NODE_ATTRPATH_VALUE@118..143 + NODE_ATTRPATH@118..122 + NODE_IDENT@118..122 + TOKEN_IDENT@118..122 "body" + TOKEN_WHITESPACE@122..123 " " + TOKEN_ASSIGN@123..124 "=" + TOKEN_WHITESPACE@124..125 " " + NODE_IDENT@125..142 + TOKEN_IDENT@125..142 "this_syntax_sucks" + TOKEN_SEMICOLON@142..143 ";" + TOKEN_WHITESPACE@143..146 "\n " + TOKEN_R_BRACE@146..147 "}" + TOKEN_SEMICOLON@147..148 ";" + TOKEN_WHITESPACE@148..149 "\n" + TOKEN_R_BRACE@149..150 "}" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/with-import-let-in.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/with-import-let-in.nix new file mode 100644 index 0000000..076eea5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/with-import-let-in.nix @@ -0,0 +1,12 @@ +with import ./simple-set.nix; + +let + a = 4 + 2; +in { + b = a + 2; + + legacy = let { + this_syntax_sucks = true; + body = this_syntax_sucks; + }; +} diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/with.expect b/third_party/crates/rnix-0.14.0/test_data/parser/success/with.expect new file mode 100644 index 0000000..c09bc59 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/with.expect @@ -0,0 +1,11 @@ +NODE_ROOT@0..20 + NODE_WITH@0..20 + TOKEN_WITH@0..4 "with" + TOKEN_WHITESPACE@4..5 " " + NODE_IDENT@5..14 + TOKEN_IDENT@5..14 "namespace" + TOKEN_SEMICOLON@14..15 ";" + TOKEN_WHITESPACE@15..16 " " + NODE_IDENT@16..20 + TOKEN_IDENT@16..20 "expr" + diff --git a/third_party/crates/rnix-0.14.0/test_data/parser/success/with.nix b/third_party/crates/rnix-0.14.0/test_data/parser/success/with.nix new file mode 100644 index 0000000..eb7c9a8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/parser/success/with.nix @@ -0,0 +1 @@ +with namespace; expr diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_double_slash_middle.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_double_slash_middle.expect new file mode 100644 index 0000000..fc92f86 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_double_slash_middle.expect @@ -0,0 +1 @@ +TOKEN_ERROR, "/foo//bar/baz" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_double_slash_middle.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_double_slash_middle.nix new file mode 100644 index 0000000..21b7bc9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_double_slash_middle.nix @@ -0,0 +1 @@ +/foo//bar/baz \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_home_double_slash.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_home_double_slash.expect new file mode 100644 index 0000000..7ab7c30 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_home_double_slash.expect @@ -0,0 +1 @@ +TOKEN_ERROR, "~//foo" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_home_double_slash.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_home_double_slash.nix new file mode 100644 index 0000000..2075c87 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_home_double_slash.nix @@ -0,0 +1 @@ +~//foo \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_interp_trailing_slash.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_interp_trailing_slash.expect new file mode 100644 index 0000000..8addf6f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_interp_trailing_slash.expect @@ -0,0 +1,5 @@ +TOKEN_PATH_REL, "./" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "foo" +TOKEN_INTERPOL_END, "}" +TOKEN_ERROR, "/" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_interp_trailing_slash.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_interp_trailing_slash.nix new file mode 100644 index 0000000..968abc8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_interp_trailing_slash.nix @@ -0,0 +1 @@ +./${foo}/ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde.expect new file mode 100644 index 0000000..df0cec1 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde.expect @@ -0,0 +1 @@ +TOKEN_ERROR, "~" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde.nix new file mode 100644 index 0000000..54bcf30 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde.nix @@ -0,0 +1 @@ +~ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde_slash.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde_slash.expect new file mode 100644 index 0000000..380a513 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde_slash.expect @@ -0,0 +1 @@ +TOKEN_ERROR, "~/" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde_slash.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde_slash.nix new file mode 100644 index 0000000..81ca0f5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_tilde_slash.nix @@ -0,0 +1 @@ +~/ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_trailing_slash.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_trailing_slash.expect new file mode 100644 index 0000000..abd12d2 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_trailing_slash.expect @@ -0,0 +1 @@ +TOKEN_ERROR, "/a/" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_trailing_slash.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_trailing_slash.nix new file mode 100644 index 0000000..6637752 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/error/path_trailing_slash.nix @@ -0,0 +1 @@ +/a/ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_interspersed.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_interspersed.expect new file mode 100644 index 0000000..60d650b --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_interspersed.expect @@ -0,0 +1,16 @@ +TOKEN_L_BRACE, "{" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "a" +TOKEN_WHITESPACE, " " +TOKEN_ASSIGN, "=" +TOKEN_WHITESPACE, " " +TOKEN_COMMENT, "/* multiline * comment */" +TOKEN_WHITESPACE, " " +TOKEN_INTEGER, "123" +TOKEN_SEMICOLON, ";" +TOKEN_COMMENT, "# single line" +TOKEN_WHITESPACE, " +" +TOKEN_R_BRACE, "}" +TOKEN_WHITESPACE, " " +TOKEN_COMMENT, "# single line at the end" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_interspersed.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_interspersed.nix new file mode 100644 index 0000000..01f133c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_interspersed.nix @@ -0,0 +1,2 @@ +{ a = /* multiline * comment */ 123;# single line +} # single line at the end diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline.expect new file mode 100644 index 0000000..ae2c2ee --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline.expect @@ -0,0 +1 @@ +TOKEN_COMMENT, "/**/" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline.nix new file mode 100644 index 0000000..9d6f459 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline.nix @@ -0,0 +1 @@ +/**/ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline2.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline2.expect new file mode 100644 index 0000000..cf13708 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline2.expect @@ -0,0 +1 @@ +TOKEN_COMMENT, "/***/" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline2.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline2.nix new file mode 100644 index 0000000..e56b212 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/comment_multiline2.nix @@ -0,0 +1 @@ +/***/ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float.expect new file mode 100644 index 0000000..21ba8aa --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float.expect @@ -0,0 +1 @@ +TOKEN_FLOAT, "1.234" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float.nix new file mode 100644 index 0000000..4064385 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float.nix @@ -0,0 +1 @@ +1.234 diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_leading_part.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_leading_part.expect new file mode 100644 index 0000000..1dc6ad3 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_leading_part.expect @@ -0,0 +1 @@ +TOKEN_FLOAT, ".5" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_leading_part.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_leading_part.nix new file mode 100644 index 0000000..d6c9fff --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_leading_part.nix @@ -0,0 +1 @@ +.5 diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_trailing_part.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_trailing_part.expect new file mode 100644 index 0000000..ba17517 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_trailing_part.expect @@ -0,0 +1 @@ +TOKEN_FLOAT, "1." diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_trailing_part.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_trailing_part.nix new file mode 100644 index 0000000..d54c6b6 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_no_trailing_part.nix @@ -0,0 +1 @@ +1. diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_lower.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_lower.expect new file mode 100644 index 0000000..10b0051 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_lower.expect @@ -0,0 +1 @@ +TOKEN_FLOAT, "1.1e4" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_lower.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_lower.nix new file mode 100644 index 0000000..6869cc4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_lower.nix @@ -0,0 +1 @@ +1.1e4 diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_neg.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_neg.expect new file mode 100644 index 0000000..9e443e9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_neg.expect @@ -0,0 +1 @@ +TOKEN_FLOAT, "123.4e-2" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_neg.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_neg.nix new file mode 100644 index 0000000..9cc694d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_neg.nix @@ -0,0 +1 @@ +123.4e-2 diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_pos.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_pos.expect new file mode 100644 index 0000000..08db40e --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_pos.expect @@ -0,0 +1 @@ +TOKEN_FLOAT, "123.4e+2" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_pos.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_pos.nix new file mode 100644 index 0000000..9b7e656 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_pos.nix @@ -0,0 +1 @@ +123.4e+2 diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_upper.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_upper.expect new file mode 100644 index 0000000..9773652 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_upper.expect @@ -0,0 +1 @@ +TOKEN_FLOAT, "1.1E4" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_upper.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_upper.nix new file mode 100644 index 0000000..e96eaa9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/float_scientific_upper.nix @@ -0,0 +1 @@ +1.1E4 diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/int.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/int.expect new file mode 100644 index 0000000..e847a86 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/int.expect @@ -0,0 +1 @@ +TOKEN_INTEGER, "42" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/int.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/int.nix new file mode 100644 index 0000000..d81cc07 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/int.nix @@ -0,0 +1 @@ +42 diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda.expect new file mode 100644 index 0000000..135d3c9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda.expect @@ -0,0 +1,11 @@ +TOKEN_IDENT, "a" +TOKEN_COLON, ":" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "b" +TOKEN_COLON, ":" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "a" +TOKEN_WHITESPACE, " " +TOKEN_ADD, "+" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "b" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda.nix new file mode 100644 index 0000000..cef5868 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda.nix @@ -0,0 +1 @@ +a: b: a + b diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda_arg_underscore.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda_arg_underscore.expect new file mode 100644 index 0000000..6211e12 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda_arg_underscore.expect @@ -0,0 +1,3 @@ +TOKEN_IDENT, "_" +TOKEN_COLON, ":" +TOKEN_IDENT, "null" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda_arg_underscore.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda_arg_underscore.nix new file mode 100644 index 0000000..10056b3 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/lambda_arg_underscore.nix @@ -0,0 +1 @@ +_:null diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_01.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_01.expect new file mode 100644 index 0000000..9133b65 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_01.expect @@ -0,0 +1,3 @@ +TOKEN_INTEGER, "01" +TOKEN_DOT, "." +TOKEN_IDENT, "e2" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_01.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_01.nix new file mode 100644 index 0000000..e4a4ffe --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_01.nix @@ -0,0 +1 @@ +01.e2 \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_02.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_02.expect new file mode 100644 index 0000000..f0e84c9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_02.expect @@ -0,0 +1,2 @@ +TOKEN_INTEGER, "01" +TOKEN_FLOAT, ".1e2" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_02.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_02.nix new file mode 100644 index 0000000..ee288d0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_edge_case_02.nix @@ -0,0 +1 @@ +01.1e2 \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_numbers.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_numbers.expect new file mode 100644 index 0000000..fa7cecf --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_numbers.expect @@ -0,0 +1,4 @@ +TOKEN_INTEGER, "001" +TOKEN_FLOAT, ".22e01" +TOKEN_FLOAT, ".30" +TOKEN_FLOAT, ".4" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_numbers.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_numbers.nix new file mode 100644 index 0000000..7f5af6f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/leading_zero_numbers.nix @@ -0,0 +1 @@ +001.22e01.30.4 \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/let.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/let.expect new file mode 100644 index 0000000..369753c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/let.expect @@ -0,0 +1,12 @@ +TOKEN_LET, "let" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "a" +TOKEN_WHITESPACE, " " +TOKEN_ASSIGN, "=" +TOKEN_WHITESPACE, " " +TOKEN_INTEGER, "3" +TOKEN_SEMICOLON, ";" +TOKEN_WHITESPACE, " " +TOKEN_IN, "in" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "a" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/let.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/let.nix new file mode 100644 index 0000000..29b8716 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/let.nix @@ -0,0 +1 @@ +let a = 3; in a diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list.expect new file mode 100644 index 0000000..ce51bce --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list.expect @@ -0,0 +1,11 @@ +TOKEN_L_BRACK, "[" +TOKEN_IDENT, "a" +TOKEN_WHITESPACE, " " +TOKEN_INTEGER, "2" +TOKEN_WHITESPACE, " " +TOKEN_INTEGER, "3" +TOKEN_WHITESPACE, " " +TOKEN_STRING_START, """ +TOKEN_STRING_CONTENT, "lol" +TOKEN_STRING_END, """ +TOKEN_R_BRACK, "]" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list.nix new file mode 100644 index 0000000..29d1219 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list.nix @@ -0,0 +1 @@ +[a 2 3 "lol"] diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list_concat.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list_concat.expect new file mode 100644 index 0000000..5f3bc98 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list_concat.expect @@ -0,0 +1,15 @@ +TOKEN_L_BRACK, "[" +TOKEN_INTEGER, "1" +TOKEN_R_BRACK, "]" +TOKEN_WHITESPACE, " " +TOKEN_CONCAT, "++" +TOKEN_WHITESPACE, " " +TOKEN_L_BRACK, "[" +TOKEN_INTEGER, "2" +TOKEN_R_BRACK, "]" +TOKEN_WHITESPACE, " " +TOKEN_CONCAT, "++" +TOKEN_WHITESPACE, " " +TOKEN_L_BRACK, "[" +TOKEN_INTEGER, "3" +TOKEN_R_BRACK, "]" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list_concat.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list_concat.nix new file mode 100644 index 0000000..a9b7501 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/list_concat.nix @@ -0,0 +1 @@ +[1] ++ [2] ++ [3] diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math.expect new file mode 100644 index 0000000..32b3e04 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math.expect @@ -0,0 +1,23 @@ +TOKEN_INTEGER, "1" +TOKEN_WHITESPACE, " " +TOKEN_ADD, "+" +TOKEN_WHITESPACE, " " +TOKEN_INTEGER, "2" +TOKEN_WHITESPACE, " " +TOKEN_MUL, "*" +TOKEN_WHITESPACE, " " +TOKEN_INTEGER, "3" +TOKEN_WHITESPACE, " " +TOKEN_ADD, "+" +TOKEN_WHITESPACE, " " +TOKEN_INTEGER, "4" +TOKEN_WHITESPACE, " " +TOKEN_DIV, "/" +TOKEN_WHITESPACE, " " +TOKEN_L_PAREN, "(" +TOKEN_INTEGER, "5" +TOKEN_WHITESPACE, " " +TOKEN_SUB, "-" +TOKEN_WHITESPACE, " " +TOKEN_INTEGER, "6" +TOKEN_R_PAREN, ")" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math.nix new file mode 100644 index 0000000..0aacfdd --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math.nix @@ -0,0 +1 @@ +1 + 2 * 3 + 4 / (5 - 6) diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_div_isnt_path.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_div_isnt_path.expect new file mode 100644 index 0000000..67f3566 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_div_isnt_path.expect @@ -0,0 +1,4 @@ +TOKEN_IDENT, "a" +TOKEN_DIV, "/" +TOKEN_WHITESPACE, " " +TOKEN_INTEGER, "3" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_div_isnt_path.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_div_isnt_path.nix new file mode 100644 index 0000000..d91c6d3 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_div_isnt_path.nix @@ -0,0 +1 @@ +a/ 3 diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_no_ws.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_no_ws.expect new file mode 100644 index 0000000..1eb1ef2 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_no_ws.expect @@ -0,0 +1,8 @@ +TOKEN_INTEGER, "5" +TOKEN_MUL, "*" +TOKEN_SUB, "-" +TOKEN_L_PAREN, "(" +TOKEN_INTEGER, "3" +TOKEN_SUB, "-" +TOKEN_INTEGER, "2" +TOKEN_R_PAREN, ")" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_no_ws.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_no_ws.nix new file mode 100644 index 0000000..252eef9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/math_no_ws.nix @@ -0,0 +1 @@ +5*-(3-2) diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_geq_isnt_path.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_geq_isnt_path.expect new file mode 100644 index 0000000..d0ac501 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_geq_isnt_path.expect @@ -0,0 +1,3 @@ +TOKEN_IDENT, "x" +TOKEN_MORE_OR_EQ, ">=" +TOKEN_IDENT, "y" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_geq_isnt_path.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_geq_isnt_path.nix new file mode 100644 index 0000000..5a30a6f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_geq_isnt_path.nix @@ -0,0 +1 @@ +x>=y diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_update.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_update.expect new file mode 100644 index 0000000..b64bc3e --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_update.expect @@ -0,0 +1,3 @@ +TOKEN_IDENT, "a" +TOKEN_UPDATE, "//" +TOKEN_IDENT, "b" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_update.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_update.nix new file mode 100644 index 0000000..c1db361 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/op_update.nix @@ -0,0 +1 @@ +a//b diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start.expect new file mode 100644 index 0000000..b81f99a --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start.expect @@ -0,0 +1,4 @@ +TOKEN_PATH_ABS, "/" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "foo" +TOKEN_INTERPOL_END, "}" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start.nix new file mode 100644 index 0000000..53f93f1 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start.nix @@ -0,0 +1 @@ +/${foo} diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start_suffix.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start_suffix.expect new file mode 100644 index 0000000..edab8b1 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start_suffix.expect @@ -0,0 +1,5 @@ +TOKEN_PATH_ABS, "/" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "foo" +TOKEN_INTERPOL_END, "}" +TOKEN_PATH_ABS, "-a" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start_suffix.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start_suffix.nix new file mode 100644 index 0000000..ac20a25 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_interp_start_suffix.nix @@ -0,0 +1 @@ +/${foo}-a diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_nix_store.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_nix_store.expect new file mode 100644 index 0000000..7c26b5c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_nix_store.expect @@ -0,0 +1 @@ +TOKEN_PATH_ABS, "/nix/store/abc123def456-package-1.0.0/bin/executable" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_nix_store.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_nix_store.nix new file mode 100644 index 0000000..e2a8626 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_abs_nix_store.nix @@ -0,0 +1 @@ +/nix/store/abc123def456-package-1.0.0/bin/executable \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_absolute.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_absolute.expect new file mode 100644 index 0000000..ed29043 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_absolute.expect @@ -0,0 +1 @@ +TOKEN_PATH_ABS, "/hello/world" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_absolute.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_absolute.nix new file mode 100644 index 0000000..f6c7a29 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_absolute.nix @@ -0,0 +1 @@ +/hello/world diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home.expect new file mode 100644 index 0000000..f7178f5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home.expect @@ -0,0 +1 @@ +TOKEN_PATH_HOME, "~/hello/world" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home.nix new file mode 100644 index 0000000..313eee0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home.nix @@ -0,0 +1 @@ +~/hello/world diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home_hidden.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home_hidden.expect new file mode 100644 index 0000000..8e9f93c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home_hidden.expect @@ -0,0 +1 @@ +TOKEN_PATH_HOME, "~/.config/nixpkgs/config.nix" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home_hidden.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home_hidden.nix new file mode 100644 index 0000000..2dbe3ad --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_home_hidden.nix @@ -0,0 +1 @@ +~/.config/nixpkgs/config.nix \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp.expect new file mode 100644 index 0000000..12c83f0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp.expect @@ -0,0 +1,4 @@ +TOKEN_PATH_REL, "./" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "foo" +TOKEN_INTERPOL_END, "}" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp.nix new file mode 100644 index 0000000..344fe20 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp.nix @@ -0,0 +1 @@ +./${foo} diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_apply.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_apply.expect new file mode 100644 index 0000000..8847b88 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_apply.expect @@ -0,0 +1,6 @@ +TOKEN_PATH_REL, "./" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "foo" +TOKEN_INTERPOL_END, "}" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "bar" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_apply.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_apply.nix new file mode 100644 index 0000000..c5c0bcf --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_apply.nix @@ -0,0 +1 @@ +./${foo} bar diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple.expect new file mode 100644 index 0000000..c08e687 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple.expect @@ -0,0 +1,7 @@ +TOKEN_PATH_REL, "./" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "foo" +TOKEN_INTERPOL_END, "}" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "bar" +TOKEN_INTERPOL_END, "}" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple.nix new file mode 100644 index 0000000..86fd8d9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple.nix @@ -0,0 +1 @@ +./${foo}${bar} diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple2.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple2.expect new file mode 100644 index 0000000..822196a --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple2.expect @@ -0,0 +1,8 @@ +TOKEN_PATH_REL, "./" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "foo" +TOKEN_INTERPOL_END, "}" +TOKEN_PATH_REL, "a" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "bar" +TOKEN_INTERPOL_END, "}" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple2.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple2.nix new file mode 100644 index 0000000..701863a --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_multiple2.nix @@ -0,0 +1 @@ +./${foo}a${bar} diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_then_plain.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_then_plain.expect new file mode 100644 index 0000000..5663841 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_then_plain.expect @@ -0,0 +1,5 @@ +TOKEN_PATH_REL, "./" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "foo" +TOKEN_INTERPOL_END, "}" +TOKEN_PATH_REL, ".jpg" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_then_plain.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_then_plain.nix new file mode 100644 index 0000000..f13166c --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_interp_then_plain.nix @@ -0,0 +1 @@ +./${foo}.jpg diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_isnt_math.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_isnt_math.expect new file mode 100644 index 0000000..eef6efa --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_isnt_math.expect @@ -0,0 +1 @@ +TOKEN_PATH_REL, "a+3/5+b" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_isnt_math.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_isnt_math.nix new file mode 100644 index 0000000..209debe --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_isnt_math.nix @@ -0,0 +1 @@ +a+3/5+b diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_no_newline.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_no_newline.expect new file mode 100644 index 0000000..9ecc59e --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_no_newline.expect @@ -0,0 +1,5 @@ +TOKEN_IDENT, "import" +TOKEN_WHITESPACE, " " +TOKEN_PATH_REL, "./." +TOKEN_WHITESPACE, " +" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_no_newline.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_no_newline.nix new file mode 100644 index 0000000..2c18eb4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_no_newline.nix @@ -0,0 +1,2 @@ +import ./. + diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_operators_mix.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_operators_mix.expect new file mode 100644 index 0000000..8d239ee --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_operators_mix.expect @@ -0,0 +1,9 @@ +TOKEN_PATH_ABS, "/foo" +TOKEN_WHITESPACE, " " +TOKEN_ADD, "+" +TOKEN_WHITESPACE, " " +TOKEN_PATH_ABS, "/bar" +TOKEN_WHITESPACE, " " +TOKEN_SUB, "-" +TOKEN_WHITESPACE, " " +TOKEN_PATH_REL, "./baz" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_operators_mix.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_operators_mix.nix new file mode 100644 index 0000000..7984b47 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_operators_mix.nix @@ -0,0 +1 @@ +/foo + /bar - ./baz \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative.expect new file mode 100644 index 0000000..2bc5054 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative.expect @@ -0,0 +1 @@ +TOKEN_PATH_REL, "hello/world" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative.nix new file mode 100644 index 0000000..3468a26 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative.nix @@ -0,0 +1 @@ +hello/world diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_complex.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_complex.expect new file mode 100644 index 0000000..7b48464 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_complex.expect @@ -0,0 +1 @@ +TOKEN_PATH_REL, "./a/b/../c/./d/e" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_complex.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_complex.nix new file mode 100644 index 0000000..eb0bf27 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_complex.nix @@ -0,0 +1 @@ +./a/b/../c/./d/e \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_prefix.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_prefix.expect new file mode 100644 index 0000000..e76c5e6 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_prefix.expect @@ -0,0 +1 @@ +TOKEN_PATH_REL, "./hello/world" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_prefix.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_prefix.nix new file mode 100644 index 0000000..2ddb0c0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_relative_prefix.nix @@ -0,0 +1 @@ +./hello/world diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_complex.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_complex.expect new file mode 100644 index 0000000..cdd1571 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_complex.expect @@ -0,0 +1 @@ +TOKEN_PATH_SEARCH, "" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_complex.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_complex.nix new file mode 100644 index 0000000..4cff468 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_complex.nix @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_with_dash.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_with_dash.expect new file mode 100644 index 0000000..884f387 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_with_dash.expect @@ -0,0 +1 @@ +TOKEN_PATH_SEARCH, "" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_with_dash.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_with_dash.nix new file mode 100644 index 0000000..38f0c4a --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_search_with_dash.nix @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_store.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_store.expect new file mode 100644 index 0000000..c97778d --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_store.expect @@ -0,0 +1 @@ +TOKEN_PATH_SEARCH, "" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_store.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_store.nix new file mode 100644 index 0000000..be45ec4 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_store.nix @@ -0,0 +1 @@ + diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_underscore.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_underscore.expect new file mode 100644 index 0000000..4770141 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_underscore.expect @@ -0,0 +1 @@ +TOKEN_PATH_REL, "hello_/world" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_underscore.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_underscore.nix new file mode 100644 index 0000000..6db18ee --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_underscore.nix @@ -0,0 +1 @@ +hello_/world diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_numbers.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_numbers.expect new file mode 100644 index 0000000..f151c90 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_numbers.expect @@ -0,0 +1 @@ +TOKEN_PATH_ABS, "/usr/lib64/libc.so.6" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_numbers.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_numbers.nix new file mode 100644 index 0000000..cbe74da --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_numbers.nix @@ -0,0 +1 @@ +/usr/lib64/libc.so.6 \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_plus.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_plus.expect new file mode 100644 index 0000000..43f5e47 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_plus.expect @@ -0,0 +1 @@ +TOKEN_PATH_REL, "./foo+bar/baz" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_plus.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_plus.nix new file mode 100644 index 0000000..9fff018 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/path_with_plus.nix @@ -0,0 +1 @@ +./foo+bar/baz \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/patterns.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/patterns.expect new file mode 100644 index 0000000..f1a5c35 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/patterns.expect @@ -0,0 +1,21 @@ +TOKEN_L_BRACE, "{" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "a" +TOKEN_COMMA, "," +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "b" +TOKEN_WHITESPACE, " " +TOKEN_QUESTION, "?" +TOKEN_WHITESPACE, " " +TOKEN_STRING_START, """ +TOKEN_STRING_CONTENT, "default" +TOKEN_STRING_END, """ +TOKEN_COMMA, "," +TOKEN_WHITESPACE, " " +TOKEN_ELLIPSIS, "..." +TOKEN_WHITESPACE, " " +TOKEN_R_BRACE, "}" +TOKEN_WHITESPACE, " " +TOKEN_AT, "@" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "outer" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/patterns.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/patterns.nix new file mode 100644 index 0000000..394b7b5 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/patterns.nix @@ -0,0 +1 @@ +{ a, b ? "default", ... } @ outer diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/select_dynamic.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/select_dynamic.expect new file mode 100644 index 0000000..fd2d16e --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/select_dynamic.expect @@ -0,0 +1,7 @@ +TOKEN_IDENT, "a" +TOKEN_DOT, "." +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "b" +TOKEN_INTERPOL_END, "}" +TOKEN_DOT, "." +TOKEN_IDENT, "c" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/select_dynamic.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/select_dynamic.nix new file mode 100644 index 0000000..aff4504 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/select_dynamic.nix @@ -0,0 +1 @@ +a.${b}.c diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string.expect new file mode 100644 index 0000000..51a7f33 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string.expect @@ -0,0 +1,3 @@ +TOKEN_STRING_START, """ +TOKEN_STRING_CONTENT, "Hello world" +TOKEN_STRING_END, """ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string.nix new file mode 100644 index 0000000..0290477 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string.nix @@ -0,0 +1 @@ +"Hello world" \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_dollar_escape.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_dollar_escape.expect new file mode 100644 index 0000000..f417862 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_dollar_escape.expect @@ -0,0 +1,3 @@ +TOKEN_STRING_START, """ +TOKEN_STRING_CONTENT, "$${test}" +TOKEN_STRING_END, """ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_dollar_escape.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_dollar_escape.nix new file mode 100644 index 0000000..f0ee6f0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_dollar_escape.nix @@ -0,0 +1 @@ +"$${test}" \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_escape.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_escape.expect new file mode 100644 index 0000000..51204a6 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_escape.expect @@ -0,0 +1,3 @@ +TOKEN_STRING_START, """ +TOKEN_STRING_CONTENT, "Hello \"World\"" +TOKEN_STRING_END, """ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_escape.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_escape.nix new file mode 100644 index 0000000..ec81910 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_escape.nix @@ -0,0 +1 @@ +"Hello \"World\"" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp.expect new file mode 100644 index 0000000..cb994ea --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp.expect @@ -0,0 +1,9 @@ +TOKEN_STRING_START, """ +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "hello" +TOKEN_INTERPOL_END, "}" +TOKEN_STRING_CONTENT, " " +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "world" +TOKEN_INTERPOL_END, "}" +TOKEN_STRING_END, """ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp.nix new file mode 100644 index 0000000..d38b420 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp.nix @@ -0,0 +1 @@ +"${hello} ${world}" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_dollar_escape.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_dollar_escape.expect new file mode 100644 index 0000000..2fa3184 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_dollar_escape.expect @@ -0,0 +1,6 @@ +TOKEN_STRING_START, """ +TOKEN_STRING_CONTENT, "\$" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "test" +TOKEN_INTERPOL_END, "}" +TOKEN_STRING_END, """ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_dollar_escape.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_dollar_escape.nix new file mode 100644 index 0000000..27120de --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_dollar_escape.nix @@ -0,0 +1 @@ +"\$${test}" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_nested.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_nested.expect new file mode 100644 index 0000000..350a964 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_nested.expect @@ -0,0 +1,9 @@ +TOKEN_STRING_START, "''" +TOKEN_INTERPOL_START, "${" +TOKEN_STRING_START, """ +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "var" +TOKEN_INTERPOL_END, "}" +TOKEN_STRING_END, """ +TOKEN_INTERPOL_END, "}" +TOKEN_STRING_END, "''" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_nested.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_nested.nix new file mode 100644 index 0000000..fcd7866 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_nested.nix @@ -0,0 +1 @@ +''${"${var}"}'' \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_select.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_select.expect new file mode 100644 index 0000000..b8a50de --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_select.expect @@ -0,0 +1,22 @@ +TOKEN_STRING_START, """ +TOKEN_STRING_CONTENT, "Hello, " +TOKEN_INTERPOL_START, "${" +TOKEN_WHITESPACE, " " +TOKEN_L_BRACE, "{" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "world" +TOKEN_WHITESPACE, " " +TOKEN_ASSIGN, "=" +TOKEN_WHITESPACE, " " +TOKEN_STRING_START, """ +TOKEN_STRING_CONTENT, "World" +TOKEN_STRING_END, """ +TOKEN_SEMICOLON, ";" +TOKEN_WHITESPACE, " " +TOKEN_R_BRACE, "}" +TOKEN_DOT, "." +TOKEN_IDENT, "world" +TOKEN_WHITESPACE, " " +TOKEN_INTERPOL_END, "}" +TOKEN_STRING_CONTENT, "!" +TOKEN_STRING_END, """ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_select.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_select.nix new file mode 100644 index 0000000..f8a8582 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_interp_select.nix @@ -0,0 +1 @@ +"Hello, ${ { world = "World"; }.world }!" \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_isnt_path.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_isnt_path.expect new file mode 100644 index 0000000..13ede0a --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_isnt_path.expect @@ -0,0 +1,6 @@ +TOKEN_STRING_START, """ +TOKEN_STRING_CONTENT, "./" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "foo" +TOKEN_INTERPOL_END, "}" +TOKEN_STRING_END, """ diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_isnt_path.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_isnt_path.nix new file mode 100644 index 0000000..8b84db9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_isnt_path.nix @@ -0,0 +1 @@ +"./${foo}" \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline.expect new file mode 100644 index 0000000..d1edac9 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline.expect @@ -0,0 +1,11 @@ +TOKEN_STRING_START, "''" +TOKEN_STRING_CONTENT, " +This is a multiline string :D + indented by two +\'\'\'\'\ +''${ interpolation was escaped } +''\${ interpolation was escaped } +two single quotes: ''' +three single quotes: '''' +" +TOKEN_STRING_END, "''" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline.nix new file mode 100644 index 0000000..939a962 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline.nix @@ -0,0 +1,9 @@ +'' +This is a multiline string :D + indented by two +\'\'\'\'\ +''${ interpolation was escaped } +''\${ interpolation was escaped } +two single quotes: ''' +three single quotes: '''' +'' \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_dollar_escape.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_dollar_escape.expect new file mode 100644 index 0000000..c49be23 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_dollar_escape.expect @@ -0,0 +1,3 @@ +TOKEN_STRING_START, "''" +TOKEN_STRING_CONTENT, "$${test}" +TOKEN_STRING_END, "''" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_dollar_escape.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_dollar_escape.nix new file mode 100644 index 0000000..8ad8949 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_dollar_escape.nix @@ -0,0 +1 @@ +''$${test}'' diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_interp_escape.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_interp_escape.expect new file mode 100644 index 0000000..f533f6b --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_interp_escape.expect @@ -0,0 +1,6 @@ +TOKEN_STRING_START, "''" +TOKEN_STRING_CONTENT, "''$" +TOKEN_INTERPOL_START, "${" +TOKEN_IDENT, "test" +TOKEN_INTERPOL_END, "}" +TOKEN_STRING_END, "''" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_interp_escape.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_interp_escape.nix new file mode 100644 index 0000000..5e5f0e0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/string_multiline_interp_escape.nix @@ -0,0 +1 @@ +''''$${test}'' diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri.expect new file mode 100644 index 0000000..e600398 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri.expect @@ -0,0 +1 @@ +TOKEN_URI, "https://google.com/?q=Hello+World" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri.nix new file mode 100644 index 0000000..4227f44 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri.nix @@ -0,0 +1 @@ +https://google.com/?q=Hello+World diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_git_ssh.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_git_ssh.expect new file mode 100644 index 0000000..1369d75 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_git_ssh.expect @@ -0,0 +1 @@ +TOKEN_URI, "git+ssh://git@github.com/NixOS/nix.git" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_git_ssh.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_git_ssh.nix new file mode 100644 index 0000000..24390ba --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_git_ssh.nix @@ -0,0 +1 @@ +git+ssh://git@github.com/NixOS/nix.git \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_https.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_https.expect new file mode 100644 index 0000000..8f27b7f --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_https.expect @@ -0,0 +1 @@ +TOKEN_URI, "https://github.com/NixOS/nixpkgs/archive/master.tar.gz" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_https.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_https.nix new file mode 100644 index 0000000..f8e54cc --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_https.nix @@ -0,0 +1 @@ +https://github.com/NixOS/nixpkgs/archive/master.tar.gz \ No newline at end of file diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_with_underscore.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_with_underscore.expect new file mode 100644 index 0000000..eb85d87 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_with_underscore.expect @@ -0,0 +1 @@ +TOKEN_URI, "https://goo_gle.com/?q=Hello+World" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_with_underscore.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_with_underscore.nix new file mode 100644 index 0000000..c501dc0 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/uri_with_underscore.nix @@ -0,0 +1 @@ +https://goo_gle.com/?q=Hello+World diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/with.expect b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/with.expect new file mode 100644 index 0000000..561d23a --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/with.expect @@ -0,0 +1,6 @@ +TOKEN_WITH, "with" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "namespace" +TOKEN_SEMICOLON, ";" +TOKEN_WHITESPACE, " " +TOKEN_IDENT, "expr" diff --git a/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/with.nix b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/with.nix new file mode 100644 index 0000000..eb7c9a8 --- /dev/null +++ b/third_party/crates/rnix-0.14.0/test_data/tokenizer/success/with.nix @@ -0,0 +1 @@ +with namespace; expr diff --git a/third_party/crates/rowan-0.16.1/.cargo-checksum.json b/third_party/crates/rowan-0.16.1/.cargo-checksum.json new file mode 100644 index 0000000..f14a83d --- /dev/null +++ b/third_party/crates/rowan-0.16.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"7d471d4f2d4a2cb6b406b0bf3d1be7d7735dc4dcfdb165cb8766a4ca48497b8c","Cargo.lock":"24dfd51d2e1720257b6a678ff5e03a594cbcf195b8fbebca0cba04c1d551c073","Cargo.toml":"cbcc91fcc6cc6034ab7b436569da02d4b9bed9eb4f70bc7f9748d580e3adfe7f","Cargo.toml.orig":"e617868c3807e231c943088bad45232395108ed4ee1991df88ddf949206d85af","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"69657dd291f7b245820ee01fa7bdbfdc5dc2b47284767641ffb8f94e9f9bc522","examples/math.rs":"e568a39431b26b20362a8fea7728efc2295f39bbb7dace3789756cfa58c7b02a","examples/s_expressions.rs":"6d963a8c030978e2648a059f2dcd5314d9fef47f0dda45e4134caedae1429eee","src/api.rs":"31c2ae43432bae7dff12d4d2d1a76c62c3f2d74a9d00828b82d38a01d61334c8","src/arc.rs":"fce42117614b3016ee7db92ec603d68ce0d06d77bd7bb5d4f569d1789a3f1809","src/ast.rs":"f6e803e1cd1099a6d80a27c8b7fda965dc664bad6d541788699fe083169971e2","src/cow_mut.rs":"c90f47a013ae8cfb00bee089b75bbc2e493424e344fb4aaeff78cb2db8558ec2","src/cursor.rs":"0b191dd7b9946e8ed0e436b9af5d13e57911a755fec788d1d87f3aee365d7489","src/green.rs":"34d58d497d2af2bbd1533aea6b4aa91496d65275b3b6def8dd6f5b1210ec0ce0","src/green/builder.rs":"cc5857e04b8b0c252c9c644397e63d204b3025bda8cb68d58750b085062f117b","src/green/element.rs":"df199a8b6adefef54398f209e7316525eaf84133e952325d46641b66cb89ada9","src/green/node.rs":"2b7358abbd7446f31bf00f4ba252682a6c6f702ca0d05e869b3ebc465879b314","src/green/node_cache.rs":"f85ca104edb7d2261fd111a6fa4165f076e802aa9414457bdb028788db8dde9d","src/green/token.rs":"fe99fdf7a76227b0025461a928d6c1484d4c70cceb326189387b1f4a37e28ea1","src/lib.rs":"e0eb1ba73978636b577094ebb726e2e222f347587928ba3930b196b809f17f86","src/serde_impls.rs":"603a459c1e3ad6edd2915e6ef3d103bae36364e01d781a8521486d618ba7b678","src/sll.rs":"3428e62b22017f89b0366e5be882a17cb449c118b99805e0c219090a41845b9a","src/syntax_text.rs":"e387fa481a53aa9dd220a350acabd150daa8440c07ade49ea8a2f69275c6b366","src/utility_types.rs":"ce0874ae3e2b1eccb77025322c4453ceafef983f5d41b442448fb848259edf06","tests/tidy.rs":"15f655d7022a23cea887c6ac52727811f72c7d6a0fd54cdbb0476521ab4fea7f"},"package":"417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21"} \ No newline at end of file diff --git a/third_party/crates/rowan-0.16.1/.cargo_vcs_info.json b/third_party/crates/rowan-0.16.1/.cargo_vcs_info.json new file mode 100644 index 0000000..44595cc --- /dev/null +++ b/third_party/crates/rowan-0.16.1/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "e25dbdf9cb7f7757eb85c74a69c8a7d4a4fae67b" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/rowan-0.16.1/BUILD.bazel b/third_party/crates/rowan-0.16.1/BUILD.bazel new file mode 100644 index 0000000..d9c3d10 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/BUILD.bazel @@ -0,0 +1,116 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "rowan", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_root = "src/lib.rs", + edition = "2021", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=rowan", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "0.16.1", + deps = [ + "//third_party/crates/countme-3.0.1:countme", + "//third_party/crates/hashbrown-0.14.5:hashbrown", + "//third_party/crates/rustc-hash-1.1.0:rustc_hash", + "//third_party/crates/text-size-1.1.1:text_size", + ], +) diff --git a/third_party/crates/rowan-0.16.1/Cargo.lock b/third_party/crates/rowan-0.16.1/Cargo.lock new file mode 100644 index 0000000..584ea0e --- /dev/null +++ b/third_party/crates/rowan-0.16.1/Cargo.lock @@ -0,0 +1,150 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "m_lexer" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e51ebf91162d585a5bae05e4779efc4a276171cb880d61dd6fab11c98467a7" +dependencies = [ + "regex", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rowan" +version = "0.16.1" +dependencies = [ + "countme", + "hashbrown", + "m_lexer", + "rustc-hash", + "serde", + "text-size", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "text-size" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" diff --git a/third_party/crates/rowan-0.16.1/Cargo.toml b/third_party/crates/rowan-0.16.1/Cargo.toml new file mode 100644 index 0000000..a9bc29b --- /dev/null +++ b/third_party/crates/rowan-0.16.1/Cargo.toml @@ -0,0 +1,75 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.77.0" +name = "rowan" +version = "0.16.1" +authors = ["Aleksey Kladov "] +build = false +exclude = [ + ".github/", + "bors.toml", + "rustfmt.toml", +] +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Library for generic lossless syntax trees" +readme = "README.md" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-analyzer/rowan" + +[lib] +name = "rowan" +path = "src/lib.rs" + +[[example]] +name = "math" +path = "examples/math.rs" + +[[example]] +name = "s_expressions" +path = "examples/s_expressions.rs" + +[[test]] +name = "tidy" +path = "tests/tidy.rs" + +[dependencies.countme] +version = "3.0.0" + +[dependencies.hashbrown] +version = "0.14.3" +features = ["inline-more"] +default-features = false + +[dependencies.rustc-hash] +version = "1.0.1" + +[dependencies.serde] +version = "1.0.89" +optional = true +default-features = false + +[dependencies.text-size] +version = "1.1.0" + +[dev-dependencies.m_lexer] +version = "0.0.4" + +[features] +serde1 = [ + "serde", + "text-size/serde", +] diff --git a/third_party/crates/rowan-0.16.1/Cargo.toml.orig b/third_party/crates/rowan-0.16.1/Cargo.toml.orig new file mode 100644 index 0000000..e2bc8c4 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/Cargo.toml.orig @@ -0,0 +1,29 @@ +[package] +name = "rowan" +version = "0.16.1" +authors = ["Aleksey Kladov "] +repository = "https://github.com/rust-analyzer/rowan" +license = "MIT OR Apache-2.0" +description = "Library for generic lossless syntax trees" +edition = "2021" +rust-version = "1.77.0" +exclude = [".github/", "bors.toml", "rustfmt.toml"] + +[workspace] +members = ["xtask"] + +[dependencies] +rustc-hash = "1.0.1" +hashbrown = { version = "0.14.3", features = [ + "inline-more", +], default-features = false } +text-size = "1.1.0" +countme = "3.0.0" + +serde = { version = "1.0.89", optional = true, default-features = false } + +[dev-dependencies] +m_lexer = "0.0.4" + +[features] +serde1 = ["serde", "text-size/serde"] diff --git a/third_party/crates/rowan-0.16.1/LICENSE-APACHE b/third_party/crates/rowan-0.16.1/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/third_party/crates/rowan-0.16.1/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/third_party/crates/rowan-0.16.1/LICENSE-MIT b/third_party/crates/rowan-0.16.1/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/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/third_party/crates/rowan-0.16.1/README.md b/third_party/crates/rowan-0.16.1/README.md new file mode 100644 index 0000000..f0d5b13 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/README.md @@ -0,0 +1,22 @@ +# Rowan + +[![Crates.io](https://img.shields.io/crates/v/rowan.svg)](https://crates.io/crates/rowan) +[![Crates.io](https://img.shields.io/crates/d/rowan.svg)](https://crates.io/crates/rowan) + +Rowan is a library for lossless syntax trees, inspired in part by +Swift's [libsyntax](https://github.com/apple/swift/tree/5e2c815edfd758f9b1309ce07bfc01c4bc20ec23/lib/Syntax). + +A conceptual overview is available in the [rust-analyzer repo](https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/syntax.md). + +See `examples/s_expressions` for a tutorial, and [rust-analyzer](https://github.com/rust-analyzer/rust-analyzer/) for real-world usage. + +## Testing + +This crate is primarily tested by various integration tests in rust-analyzer. + +## License + +Rowan is primarily 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/third_party/crates/rowan-0.16.1/examples/math.rs b/third_party/crates/rowan-0.16.1/examples/math.rs new file mode 100644 index 0000000..e3c3505 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/examples/math.rs @@ -0,0 +1,152 @@ +//! Example that takes the input +//! 1 + 2 * 3 + 4 +//! and builds the tree +//! - Marker(Root) +//! - Marker(Operation) +//! - Marker(Operation) +//! - "1" Token(Number) +//! - "+" Token(Add) +//! - Marker(Operation) +//! - "2" Token(Number) +//! - "*" Token(Mul) +//! - "3" Token(Number) +//! - "+" Token(Add) +//! - "4" Token(Number) + +use rowan::{GreenNodeBuilder, NodeOrToken}; +use std::iter::Peekable; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(non_camel_case_types)] +#[repr(u16)] +enum SyntaxKind { + WHITESPACE = 0, + + ADD, + SUB, + MUL, + DIV, + + NUMBER, + ERROR, + OPERATION, + ROOT, +} +use SyntaxKind::*; + +impl From for rowan::SyntaxKind { + fn from(kind: SyntaxKind) -> Self { + Self(kind as u16) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +enum Lang {} +impl rowan::Language for Lang { + type Kind = SyntaxKind; + fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind { + assert!(raw.0 <= ROOT as u16); + unsafe { std::mem::transmute::(raw.0) } + } + fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind { + kind.into() + } +} + +type SyntaxNode = rowan::SyntaxNode; +#[allow(unused)] +type SyntaxToken = rowan::SyntaxToken; +#[allow(unused)] +type SyntaxElement = rowan::NodeOrToken; + +struct Parser> { + builder: GreenNodeBuilder<'static>, + iter: Peekable, +} +impl> Parser { + fn peek(&mut self) -> Option { + while self.iter.peek().map(|&(t, _)| t == WHITESPACE).unwrap_or(false) { + self.bump(); + } + self.iter.peek().map(|&(t, _)| t) + } + fn bump(&mut self) { + if let Some((token, string)) = self.iter.next() { + self.builder.token(token.into(), string.as_str()); + } + } + fn parse_val(&mut self) { + match self.peek() { + Some(NUMBER) => self.bump(), + _ => { + self.builder.start_node(ERROR.into()); + self.bump(); + self.builder.finish_node(); + } + } + } + fn handle_operation(&mut self, tokens: &[SyntaxKind], next: fn(&mut Self)) { + let checkpoint = self.builder.checkpoint(); + next(self); + while self.peek().map(|t| tokens.contains(&t)).unwrap_or(false) { + self.builder.start_node_at(checkpoint, OPERATION.into()); + self.bump(); + next(self); + self.builder.finish_node(); + } + } + fn parse_mul(&mut self) { + self.handle_operation(&[MUL, DIV], Self::parse_val) + } + fn parse_add(&mut self) { + self.handle_operation(&[ADD, SUB], Self::parse_mul) + } + fn parse(mut self) -> SyntaxNode { + self.builder.start_node(ROOT.into()); + self.parse_add(); + self.builder.finish_node(); + + SyntaxNode::new_root(self.builder.finish()) + } +} + +fn print(indent: usize, element: SyntaxElement) { + let kind: SyntaxKind = element.kind(); + print!("{:indent$}", "", indent = indent); + match element { + NodeOrToken::Node(node) => { + println!("- {:?}", kind); + for child in node.children_with_tokens() { + print(indent + 2, child); + } + } + + NodeOrToken::Token(token) => println!("- {:?} {:?}", token.text(), kind), + } +} + +fn main() { + let ast = Parser { + builder: GreenNodeBuilder::new(), + iter: vec![ + // 1 + 2 * 3 + 4 + (NUMBER, "1".into()), + (WHITESPACE, " ".into()), + (ADD, "+".into()), + (WHITESPACE, " ".into()), + (NUMBER, "2".into()), + (WHITESPACE, " ".into()), + (MUL, "*".into()), + (WHITESPACE, " ".into()), + (NUMBER, "3".into()), + (WHITESPACE, " ".into()), + (ADD, "+".into()), + (WHITESPACE, " ".into()), + (NUMBER, "4".into()), + ] + .into_iter() + .peekable(), + } + .parse(); + print(0, ast.into()); +} diff --git a/third_party/crates/rowan-0.16.1/examples/s_expressions.rs b/third_party/crates/rowan-0.16.1/examples/s_expressions.rs new file mode 100644 index 0000000..e7df4c6 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/examples/s_expressions.rs @@ -0,0 +1,425 @@ +//! In this tutorial, we will write parser +//! and evaluator of arithmetic S-expressions, +//! which look like this: +//! ``` +//! (+ (* 15 2) 62) +//! ``` +//! +//! It's suggested to read the conceptual overview of the design +//! alongside this tutorial: +//! https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/syntax.md + +/// Let's start with defining all kinds of tokens and +/// composite nodes. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(non_camel_case_types)] +#[repr(u16)] +enum SyntaxKind { + L_PAREN = 0, // '(' + R_PAREN, // ')' + WORD, // '+', '15' + WHITESPACE, // whitespaces is explicit + ERROR, // as well as errors + + // composite nodes + LIST, // `(+ 2 3)` + ATOM, // `+`, `15`, wraps a WORD token + ROOT, // top-level node: a list of s-expressions +} +use SyntaxKind::*; + +/// Some boilerplate is needed, as rowan settled on using its own +/// `struct SyntaxKind(u16)` internally, instead of accepting the +/// user's `enum SyntaxKind` as a type parameter. +/// +/// First, to easily pass the enum variants into rowan via `.into()`: +impl From for rowan::SyntaxKind { + fn from(kind: SyntaxKind) -> Self { + Self(kind as u16) + } +} + +/// Second, implementing the `Language` trait teaches rowan to convert between +/// these two SyntaxKind types, allowing for a nicer SyntaxNode API where +/// "kinds" are values from our `enum SyntaxKind`, instead of plain u16 values. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +enum Lang {} +impl rowan::Language for Lang { + type Kind = SyntaxKind; + fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind { + assert!(raw.0 <= ROOT as u16); + unsafe { std::mem::transmute::(raw.0) } + } + fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind { + kind.into() + } +} + +/// GreenNode is an immutable tree, which is cheap to change, +/// but doesn't contain offsets and parent pointers. +use rowan::GreenNode; + +/// You can construct GreenNodes by hand, but a builder +/// is helpful for top-down parsers: it maintains a stack +/// of currently in-progress nodes +use rowan::GreenNodeBuilder; + +/// The parse results are stored as a "green tree". +/// We'll discuss working with the results later +struct Parse { + green_node: GreenNode, + #[allow(unused)] + errors: Vec, +} + +/// Now, let's write a parser. +/// Note that `parse` does not return a `Result`: +/// by design, syntax tree can be built even for +/// completely invalid source code. +fn parse(text: &str) -> Parse { + struct Parser { + /// input tokens, including whitespace, + /// in *reverse* order. + tokens: Vec<(SyntaxKind, String)>, + /// the in-progress tree. + builder: GreenNodeBuilder<'static>, + /// the list of syntax errors we've accumulated + /// so far. + errors: Vec, + } + + /// The outcome of parsing a single S-expression + enum SexpRes { + /// An S-expression (i.e. an atom, or a list) was successfully parsed + Ok, + /// Nothing was parsed, as no significant tokens remained + Eof, + /// An unexpected ')' was found + RParen, + } + + impl Parser { + fn parse(mut self) -> Parse { + // Make sure that the root node covers all source + self.builder.start_node(ROOT.into()); + // Parse zero or more S-expressions + loop { + match self.sexp() { + SexpRes::Eof => break, + SexpRes::RParen => { + self.builder.start_node(ERROR.into()); + self.errors.push("unmatched `)`".to_string()); + self.bump(); // be sure to chug along in case of error + self.builder.finish_node(); + } + SexpRes::Ok => (), + } + } + // Don't forget to eat *trailing* whitespace + self.skip_ws(); + // Close the root node. + self.builder.finish_node(); + + // Turn the builder into a GreenNode + Parse { green_node: self.builder.finish(), errors: self.errors } + } + fn list(&mut self) { + assert_eq!(self.current(), Some(L_PAREN)); + // Start the list node + self.builder.start_node(LIST.into()); + self.bump(); // '(' + loop { + match self.sexp() { + SexpRes::Eof => { + self.errors.push("expected `)`".to_string()); + break; + } + SexpRes::RParen => { + self.bump(); + break; + } + SexpRes::Ok => (), + } + } + // close the list node + self.builder.finish_node(); + } + fn sexp(&mut self) -> SexpRes { + // Eat leading whitespace + self.skip_ws(); + // Either a list, an atom, a closing paren, + // or an eof. + let t = match self.current() { + None => return SexpRes::Eof, + Some(R_PAREN) => return SexpRes::RParen, + Some(t) => t, + }; + match t { + L_PAREN => self.list(), + WORD => { + self.builder.start_node(ATOM.into()); + self.bump(); + self.builder.finish_node(); + } + ERROR => self.bump(), + _ => unreachable!(), + } + SexpRes::Ok + } + /// Advance one token, adding it to the current branch of the tree builder. + fn bump(&mut self) { + let (kind, text) = self.tokens.pop().unwrap(); + self.builder.token(kind.into(), text.as_str()); + } + /// Peek at the first unprocessed token + fn current(&self) -> Option { + self.tokens.last().map(|(kind, _)| *kind) + } + fn skip_ws(&mut self) { + while self.current() == Some(WHITESPACE) { + self.bump() + } + } + } + + let mut tokens = lex(text); + tokens.reverse(); + Parser { tokens, builder: GreenNodeBuilder::new(), errors: Vec::new() }.parse() +} + +/// To work with the parse results we need a view into the +/// green tree - the Syntax tree. +/// It is also immutable, like a GreenNode, +/// but it contains parent pointers, offsets, and +/// has identity semantics. + +type SyntaxNode = rowan::SyntaxNode; +#[allow(unused)] +type SyntaxToken = rowan::SyntaxToken; +#[allow(unused)] +type SyntaxElement = rowan::NodeOrToken; + +impl Parse { + fn syntax(&self) -> SyntaxNode { + SyntaxNode::new_root(self.green_node.clone()) + } +} + +/// Let's check that the parser works as expected +#[test] +fn test_parser() { + let text = "(+ (* 15 2) 62)"; + let node = parse(text).syntax(); + assert_eq!( + format!("{:?}", node), + "ROOT@0..15", // root node, spanning 15 bytes + ); + assert_eq!(node.children().count(), 1); + let list = node.children().next().unwrap(); + let children = list + .children_with_tokens() + .map(|child| format!("{:?}@{:?}", child.kind(), child.text_range())) + .collect::>(); + + assert_eq!( + children, + vec![ + "L_PAREN@0..1".to_string(), + "ATOM@1..2".to_string(), + "WHITESPACE@2..3".to_string(), // note, explicit whitespace! + "LIST@3..11".to_string(), + "WHITESPACE@11..12".to_string(), + "ATOM@12..14".to_string(), + "R_PAREN@14..15".to_string(), + ] + ); +} + +/// So far, we've been working with a homogeneous untyped tree. +/// It's nice to provide generic tree operations, like traversals, +/// but it's a bad fit for semantic analysis. +/// This crate itself does not provide AST facilities directly, +/// but it is possible to layer AST on top of `SyntaxNode` API. +/// Let's write a function to evaluate S-expression. +/// +/// For that, let's define AST nodes. +/// It'll be quite a bunch of repetitive code, so we'll use a macro. +/// +/// For a real language, you'd want to generate an AST. I find a +/// combination of `serde`, `ron` and `tera` crates invaluable for that! +macro_rules! ast_node { + ($ast:ident, $kind:ident) => { + #[derive(PartialEq, Eq, Hash)] + #[repr(transparent)] + struct $ast(SyntaxNode); + impl $ast { + #[allow(unused)] + fn cast(node: SyntaxNode) -> Option { + if node.kind() == $kind { + Some(Self(node)) + } else { + None + } + } + } + }; +} + +ast_node!(Root, ROOT); +ast_node!(Atom, ATOM); +ast_node!(List, LIST); + +// Sexp is slightly different, so let's do it by hand. +#[derive(PartialEq, Eq, Hash)] +#[repr(transparent)] +struct Sexp(SyntaxNode); + +enum SexpKind { + Atom(Atom), + List(List), +} + +impl Sexp { + fn cast(node: SyntaxNode) -> Option { + if Atom::cast(node.clone()).is_some() || List::cast(node.clone()).is_some() { + Some(Sexp(node)) + } else { + None + } + } + + fn kind(&self) -> SexpKind { + Atom::cast(self.0.clone()) + .map(SexpKind::Atom) + .or_else(|| List::cast(self.0.clone()).map(SexpKind::List)) + .unwrap() + } +} + +// Let's enhance AST nodes with ancillary functions and +// eval. +impl Root { + fn sexps(&self) -> impl Iterator + '_ { + self.0.children().filter_map(Sexp::cast) + } +} + +enum Op { + Add, + Sub, + Div, + Mul, +} + +impl Atom { + fn eval(&self) -> Option { + self.text().parse().ok() + } + fn as_op(&self) -> Option { + let op = match self.text().as_str() { + "+" => Op::Add, + "-" => Op::Sub, + "*" => Op::Mul, + "/" => Op::Div, + _ => return None, + }; + Some(op) + } + fn text(&self) -> String { + match self.0.green().children().next() { + Some(rowan::NodeOrToken::Token(token)) => token.text().to_string(), + _ => unreachable!(), + } + } +} + +impl List { + fn sexps(&self) -> impl Iterator + '_ { + self.0.children().filter_map(Sexp::cast) + } + fn eval(&self) -> Option { + let op = match self.sexps().nth(0)?.kind() { + SexpKind::Atom(atom) => atom.as_op()?, + _ => return None, + }; + let arg1 = self.sexps().nth(1)?.eval()?; + let arg2 = self.sexps().nth(2)?.eval()?; + let res = match op { + Op::Add => arg1 + arg2, + Op::Sub => arg1 - arg2, + Op::Mul => arg1 * arg2, + Op::Div if arg2 == 0 => return None, + Op::Div => arg1 / arg2, + }; + Some(res) + } +} + +impl Sexp { + fn eval(&self) -> Option { + match self.kind() { + SexpKind::Atom(atom) => atom.eval(), + SexpKind::List(list) => list.eval(), + } + } +} + +impl Parse { + fn root(&self) -> Root { + Root::cast(self.syntax()).unwrap() + } +} + +/// Let's test the eval! +fn main() { + let sexps = " +92 +(+ 62 30) +(/ 92 0) +nan +(+ (* 15 2) 62) +"; + let root = parse(sexps).root(); + let res = root.sexps().map(|it| it.eval()).collect::>(); + eprintln!("{:?}", res); + assert_eq!(res, vec![Some(92), Some(92), None, None, Some(92),]) +} + +/// Split the input string into a flat list of tokens +/// (such as L_PAREN, WORD, and WHITESPACE) +fn lex(text: &str) -> Vec<(SyntaxKind, String)> { + fn tok(t: SyntaxKind) -> m_lexer::TokenKind { + m_lexer::TokenKind(rowan::SyntaxKind::from(t).0) + } + fn kind(t: m_lexer::TokenKind) -> SyntaxKind { + match t.0 { + 0 => L_PAREN, + 1 => R_PAREN, + 2 => WORD, + 3 => WHITESPACE, + 4 => ERROR, + _ => unreachable!(), + } + } + + let lexer = m_lexer::LexerBuilder::new() + .error_token(tok(ERROR)) + .tokens(&[ + (tok(L_PAREN), r"\("), + (tok(R_PAREN), r"\)"), + (tok(WORD), r"[^\s()]+"), + (tok(WHITESPACE), r"\s+"), + ]) + .build(); + + lexer + .tokenize(text) + .into_iter() + .map(|t| (t.len, kind(t.kind))) + .scan(0usize, |start_offset, (len, kind)| { + let s: String = text[*start_offset..*start_offset + len].into(); + *start_offset += len; + Some((kind, s)) + }) + .collect() +} diff --git a/third_party/crates/rowan-0.16.1/src/api.rs b/third_party/crates/rowan-0.16.1/src/api.rs new file mode 100644 index 0000000..a877fdd --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/api.rs @@ -0,0 +1,554 @@ +use std::{borrow::Cow, fmt, iter, marker::PhantomData, ops::Range}; + +use crate::{ + cursor, green::GreenTokenData, Direction, GreenNode, GreenNodeData, GreenToken, NodeOrToken, + SyntaxKind, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent, +}; + +pub trait Language: Sized + Copy + fmt::Debug + Eq + Ord + std::hash::Hash { + type Kind: Sized + Copy + fmt::Debug + Eq + Ord + std::hash::Hash; + + fn kind_from_raw(raw: SyntaxKind) -> Self::Kind; + fn kind_to_raw(kind: Self::Kind) -> SyntaxKind; +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct SyntaxNode { + raw: cursor::SyntaxNode, + _p: PhantomData, +} + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct SyntaxToken { + raw: cursor::SyntaxToken, + _p: PhantomData, +} + +pub type SyntaxElement = NodeOrToken, SyntaxToken>; + +impl fmt::Debug for SyntaxNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.alternate() { + let mut level = 0; + for event in self.preorder_with_tokens() { + match event { + WalkEvent::Enter(element) => { + for _ in 0..level { + write!(f, " ")?; + } + match element { + NodeOrToken::Node(node) => writeln!(f, "{:?}", node)?, + NodeOrToken::Token(token) => writeln!(f, "{:?}", token)?, + } + level += 1; + } + WalkEvent::Leave(_) => level -= 1, + } + } + assert_eq!(level, 0); + Ok(()) + } else { + write!(f, "{:?}@{:?}", self.kind(), self.text_range()) + } + } +} + +impl fmt::Display for SyntaxNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.raw, f) + } +} + +impl fmt::Debug for SyntaxToken { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}@{:?}", self.kind(), self.text_range())?; + if self.text().len() < 25 { + return write!(f, " {:?}", self.text()); + } + let text = self.text(); + for idx in 21..25 { + if text.is_char_boundary(idx) { + let text = format!("{} ...", &text[..idx]); + return write!(f, " {:?}", text); + } + } + unreachable!() + } +} + +impl fmt::Display for SyntaxToken { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.raw, f) + } +} + +impl From> for SyntaxElement { + fn from(node: SyntaxNode) -> SyntaxElement { + NodeOrToken::Node(node) + } +} + +impl From> for SyntaxElement { + fn from(token: SyntaxToken) -> SyntaxElement { + NodeOrToken::Token(token) + } +} + +impl SyntaxNode { + pub fn new_root(green: GreenNode) -> SyntaxNode { + SyntaxNode::from(cursor::SyntaxNode::new_root(green)) + } + pub fn new_root_mut(green: GreenNode) -> SyntaxNode { + SyntaxNode::from(cursor::SyntaxNode::new_root_mut(green)) + } + + /// Returns a green tree, equal to the green tree this node + /// belongs to, except with this node substituted. The complexity + /// of the operation is proportional to the depth of the tree. + pub fn replace_with(&self, replacement: GreenNode) -> GreenNode { + self.raw.replace_with(replacement) + } + + pub fn kind(&self) -> L::Kind { + L::kind_from_raw(self.raw.kind()) + } + + pub fn text_range(&self) -> TextRange { + self.raw.text_range() + } + + pub fn index(&self) -> usize { + self.raw.index() + } + + pub fn text(&self) -> SyntaxText { + self.raw.text() + } + + pub fn green(&self) -> Cow<'_, GreenNodeData> { + self.raw.green() + } + + pub fn parent(&self) -> Option> { + self.raw.parent().map(Self::from) + } + + pub fn ancestors(&self) -> impl Iterator> { + self.raw.ancestors().map(SyntaxNode::from) + } + + pub fn children(&self) -> SyntaxNodeChildren { + SyntaxNodeChildren { raw: self.raw.children(), _p: PhantomData } + } + + pub fn children_with_tokens(&self) -> SyntaxElementChildren { + SyntaxElementChildren { raw: self.raw.children_with_tokens(), _p: PhantomData } + } + + pub fn first_child(&self) -> Option> { + self.raw.first_child().map(Self::from) + } + + pub fn first_child_by_kind(&self, matcher: &impl Fn(L::Kind) -> bool) -> Option> { + self.raw + .first_child_by_kind(&|raw_kind| matcher(L::kind_from_raw(raw_kind))) + .map(Self::from) + } + + pub fn last_child(&self) -> Option> { + self.raw.last_child().map(Self::from) + } + + pub fn first_child_or_token(&self) -> Option> { + self.raw.first_child_or_token().map(NodeOrToken::from) + } + + pub fn first_child_or_token_by_kind( + &self, + matcher: &impl Fn(L::Kind) -> bool, + ) -> Option> { + self.raw + .first_child_or_token_by_kind(&|raw_kind| matcher(L::kind_from_raw(raw_kind))) + .map(NodeOrToken::from) + } + + pub fn last_child_or_token(&self) -> Option> { + self.raw.last_child_or_token().map(NodeOrToken::from) + } + + pub fn next_sibling(&self) -> Option> { + self.raw.next_sibling().map(Self::from) + } + + pub fn next_sibling_by_kind( + &self, + matcher: &impl Fn(L::Kind) -> bool, + ) -> Option> { + self.raw + .next_sibling_by_kind(&|raw_kind| matcher(L::kind_from_raw(raw_kind))) + .map(Self::from) + } + + pub fn prev_sibling(&self) -> Option> { + self.raw.prev_sibling().map(Self::from) + } + + pub fn next_sibling_or_token(&self) -> Option> { + self.raw.next_sibling_or_token().map(NodeOrToken::from) + } + + pub fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(L::Kind) -> bool, + ) -> Option> { + self.raw + .next_sibling_or_token_by_kind(&|raw_kind| matcher(L::kind_from_raw(raw_kind))) + .map(NodeOrToken::from) + } + + pub fn prev_sibling_or_token(&self) -> Option> { + self.raw.prev_sibling_or_token().map(NodeOrToken::from) + } + + /// Return the leftmost token in the subtree of this node. + pub fn first_token(&self) -> Option> { + self.raw.first_token().map(SyntaxToken::from) + } + /// Return the rightmost token in the subtree of this node. + pub fn last_token(&self) -> Option> { + self.raw.last_token().map(SyntaxToken::from) + } + + pub fn siblings(&self, direction: Direction) -> impl Iterator> { + self.raw.siblings(direction).map(SyntaxNode::from) + } + + pub fn siblings_with_tokens( + &self, + direction: Direction, + ) -> impl Iterator> { + self.raw.siblings_with_tokens(direction).map(SyntaxElement::from) + } + + pub fn descendants(&self) -> impl Iterator> { + self.raw.descendants().map(SyntaxNode::from) + } + + pub fn descendants_with_tokens(&self) -> impl Iterator> { + self.raw.descendants_with_tokens().map(NodeOrToken::from) + } + + /// Traverse the subtree rooted at the current node (including the current + /// node) in preorder, excluding tokens. + pub fn preorder(&self) -> Preorder { + Preorder { raw: self.raw.preorder(), _p: PhantomData } + } + + /// Traverse the subtree rooted at the current node (including the current + /// node) in preorder, including tokens. + pub fn preorder_with_tokens(&self) -> PreorderWithTokens { + PreorderWithTokens { raw: self.raw.preorder_with_tokens(), _p: PhantomData } + } + + /// Find a token in the subtree corresponding to this node, which covers the offset. + /// Precondition: offset must be within node's range. + pub fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset> { + self.raw.token_at_offset(offset).map(SyntaxToken::from) + } + + /// Return the deepest node or token in the current subtree that fully + /// contains the range. If the range is empty and is contained in two leaf + /// nodes, either one can be returned. Precondition: range must be contained + /// within the current node + pub fn covering_element(&self, range: TextRange) -> SyntaxElement { + NodeOrToken::from(self.raw.covering_element(range)) + } + + /// Finds a [`SyntaxElement`] which intersects with a given `range`. If + /// there are several intersecting elements, any one can be returned. + /// + /// The method uses binary search internally, so it's complexity is + /// `O(log(N))` where `N = self.children_with_tokens().count()`. + pub fn child_or_token_at_range(&self, range: TextRange) -> Option> { + self.raw.child_or_token_at_range(range).map(SyntaxElement::from) + } + + /// Returns an independent copy of the subtree rooted at this node. + /// + /// The parent of the returned node will be `None`, the start offset will be + /// zero, but, otherwise, it'll be equivalent to the source node. + pub fn clone_subtree(&self) -> SyntaxNode { + SyntaxNode::from(self.raw.clone_subtree()) + } + + pub fn clone_for_update(&self) -> SyntaxNode { + SyntaxNode::from(self.raw.clone_for_update()) + } + + pub fn is_mutable(&self) -> bool { + self.raw.is_mutable() + } + + pub fn detach(&self) { + self.raw.detach() + } + + pub fn splice_children>>( + &self, + to_delete: Range, + to_insert: I, + ) { + let to_insert = to_insert.into_iter().map(cursor::SyntaxElement::from); + self.raw.splice_children(to_delete, to_insert) + } +} + +impl SyntaxToken { + /// Returns a green tree, equal to the green tree this token + /// belongs to, except with this token substituted. The complexity + /// of the operation is proportional to the depth of the tree. + pub fn replace_with(&self, new_token: GreenToken) -> GreenNode { + self.raw.replace_with(new_token) + } + + pub fn kind(&self) -> L::Kind { + L::kind_from_raw(self.raw.kind()) + } + + pub fn text_range(&self) -> TextRange { + self.raw.text_range() + } + + pub fn index(&self) -> usize { + self.raw.index() + } + + pub fn text(&self) -> &str { + self.raw.text() + } + + pub fn green(&self) -> &GreenTokenData { + self.raw.green() + } + + pub fn parent(&self) -> Option> { + self.raw.parent().map(SyntaxNode::from) + } + + /// Iterator over all the ancestors of this token excluding itself. + #[deprecated = "use `SyntaxToken::parent_ancestors` instead"] + pub fn ancestors(&self) -> impl Iterator> { + self.parent_ancestors() + } + + /// Iterator over all the ancestors of this token excluding itself. + pub fn parent_ancestors(&self) -> impl Iterator> { + self.raw.ancestors().map(SyntaxNode::from) + } + + pub fn next_sibling_or_token(&self) -> Option> { + self.raw.next_sibling_or_token().map(NodeOrToken::from) + } + pub fn prev_sibling_or_token(&self) -> Option> { + self.raw.prev_sibling_or_token().map(NodeOrToken::from) + } + + pub fn siblings_with_tokens( + &self, + direction: Direction, + ) -> impl Iterator> { + self.raw.siblings_with_tokens(direction).map(SyntaxElement::from) + } + + /// Next token in the tree (i.e, not necessary a sibling). + pub fn next_token(&self) -> Option> { + self.raw.next_token().map(SyntaxToken::from) + } + /// Previous token in the tree (i.e, not necessary a sibling). + pub fn prev_token(&self) -> Option> { + self.raw.prev_token().map(SyntaxToken::from) + } + + pub fn detach(&self) { + self.raw.detach() + } +} + +impl SyntaxElement { + pub fn text_range(&self) -> TextRange { + match self { + NodeOrToken::Node(it) => it.text_range(), + NodeOrToken::Token(it) => it.text_range(), + } + } + + pub fn index(&self) -> usize { + match self { + NodeOrToken::Node(it) => it.index(), + NodeOrToken::Token(it) => it.index(), + } + } + + pub fn kind(&self) -> L::Kind { + match self { + NodeOrToken::Node(it) => it.kind(), + NodeOrToken::Token(it) => it.kind(), + } + } + + pub fn parent(&self) -> Option> { + match self { + NodeOrToken::Node(it) => it.parent(), + NodeOrToken::Token(it) => it.parent(), + } + } + + pub fn ancestors(&self) -> impl Iterator> { + let first = match self { + NodeOrToken::Node(it) => Some(it.clone()), + NodeOrToken::Token(it) => it.parent(), + }; + iter::successors(first, SyntaxNode::parent) + } + + pub fn next_sibling_or_token(&self) -> Option> { + match self { + NodeOrToken::Node(it) => it.next_sibling_or_token(), + NodeOrToken::Token(it) => it.next_sibling_or_token(), + } + } + pub fn prev_sibling_or_token(&self) -> Option> { + match self { + NodeOrToken::Node(it) => it.prev_sibling_or_token(), + NodeOrToken::Token(it) => it.prev_sibling_or_token(), + } + } + pub fn detach(&self) { + match self { + NodeOrToken::Node(it) => it.detach(), + NodeOrToken::Token(it) => it.detach(), + } + } +} + +#[derive(Debug, Clone)] +pub struct SyntaxNodeChildren { + raw: cursor::SyntaxNodeChildren, + _p: PhantomData, +} + +impl Iterator for SyntaxNodeChildren { + type Item = SyntaxNode; + fn next(&mut self) -> Option { + self.raw.next().map(SyntaxNode::from) + } +} + +impl SyntaxNodeChildren { + pub fn by_kind(self, matcher: impl Fn(L::Kind) -> bool) -> impl Iterator> { + self.raw + .by_kind(move |raw_kind| matcher(L::kind_from_raw(raw_kind))) + .into_iter() + .map(SyntaxNode::from) + } +} + +#[derive(Debug, Clone)] +pub struct SyntaxElementChildren { + raw: cursor::SyntaxElementChildren, + _p: PhantomData, +} + +impl Iterator for SyntaxElementChildren { + type Item = SyntaxElement; + fn next(&mut self) -> Option { + self.raw.next().map(NodeOrToken::from) + } +} + +impl SyntaxElementChildren { + pub fn by_kind( + self, + matcher: impl Fn(L::Kind) -> bool, + ) -> impl Iterator> { + self.raw.by_kind(move |raw_kind| matcher(L::kind_from_raw(raw_kind))).map(NodeOrToken::from) + } +} + +pub struct Preorder { + raw: cursor::Preorder, + _p: PhantomData, +} + +impl Preorder { + pub fn skip_subtree(&mut self) { + self.raw.skip_subtree() + } +} + +impl Iterator for Preorder { + type Item = WalkEvent>; + fn next(&mut self) -> Option { + self.raw.next().map(|it| it.map(SyntaxNode::from)) + } +} + +pub struct PreorderWithTokens { + raw: cursor::PreorderWithTokens, + _p: PhantomData, +} + +impl PreorderWithTokens { + pub fn skip_subtree(&mut self) { + self.raw.skip_subtree() + } +} + +impl Iterator for PreorderWithTokens { + type Item = WalkEvent>; + fn next(&mut self) -> Option { + self.raw.next().map(|it| it.map(SyntaxElement::from)) + } +} + +impl From for SyntaxNode { + fn from(raw: cursor::SyntaxNode) -> SyntaxNode { + SyntaxNode { raw, _p: PhantomData } + } +} + +impl From> for cursor::SyntaxNode { + fn from(node: SyntaxNode) -> cursor::SyntaxNode { + node.raw + } +} + +impl From for SyntaxToken { + fn from(raw: cursor::SyntaxToken) -> SyntaxToken { + SyntaxToken { raw, _p: PhantomData } + } +} + +impl From> for cursor::SyntaxToken { + fn from(token: SyntaxToken) -> cursor::SyntaxToken { + token.raw + } +} + +impl From for SyntaxElement { + fn from(raw: cursor::SyntaxElement) -> SyntaxElement { + match raw { + NodeOrToken::Node(it) => NodeOrToken::Node(it.into()), + NodeOrToken::Token(it) => NodeOrToken::Token(it.into()), + } + } +} + +impl From> for cursor::SyntaxElement { + fn from(element: SyntaxElement) -> cursor::SyntaxElement { + match element { + NodeOrToken::Node(it) => NodeOrToken::Node(it.into()), + NodeOrToken::Token(it) => NodeOrToken::Token(it.into()), + } + } +} diff --git a/third_party/crates/rowan-0.16.1/src/arc.rs b/third_party/crates/rowan-0.16.1/src/arc.rs new file mode 100644 index 0000000..cb6758e --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/arc.rs @@ -0,0 +1,458 @@ +//! Vendored and stripped down version of triomphe +use std::{ + alloc::{self, Layout}, + cmp::Ordering, + hash::{Hash, Hasher}, + marker::PhantomData, + mem::{self, offset_of, ManuallyDrop}, + ops::Deref, + ptr, + sync::atomic::{ + self, + Ordering::{Acquire, Relaxed, Release}, + }, +}; + +/// A soft limit on the amount of references that may be made to an `Arc`. +/// +/// Going above this limit will abort your program (although not +/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. +const MAX_REFCOUNT: usize = (isize::MAX) as usize; + +/// The object allocated by an Arc +#[repr(C)] +pub(crate) struct ArcInner { + pub(crate) count: atomic::AtomicUsize, + pub(crate) data: T, +} + +unsafe impl Send for ArcInner {} +unsafe impl Sync for ArcInner {} + +/// An atomically reference counted shared pointer +/// +/// See the documentation for [`Arc`] in the standard library. Unlike the +/// standard library `Arc`, this `Arc` does not support weak reference counting. +/// +/// [`Arc`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html +#[repr(transparent)] +pub(crate) struct Arc { + pub(crate) p: ptr::NonNull>, + pub(crate) phantom: PhantomData, +} + +unsafe impl Send for Arc {} +unsafe impl Sync for Arc {} + +impl Arc { + /// Reconstruct the Arc from a raw pointer obtained from into_raw() + /// + /// Note: This raw pointer will be offset in the allocation and must be preceded + /// by the atomic count. + /// + /// It is recommended to use OffsetArc for this + #[inline] + pub(crate) unsafe fn from_raw(ptr: *const T) -> Self { + // To find the corresponding pointer to the `ArcInner` we need + // to subtract the offset of the `data` field from the pointer. + let ptr = (ptr as *const u8).sub(offset_of!(ArcInner, data)); + Arc { p: ptr::NonNull::new_unchecked(ptr as *mut ArcInner), phantom: PhantomData } + } +} + +impl Arc { + #[inline] + fn inner(&self) -> &ArcInner { + // This unsafety is ok because while this arc is alive we're guaranteed + // that the inner pointer is valid. Furthermore, we know that the + // `ArcInner` structure itself is `Sync` because the inner data is + // `Sync` as well, so we're ok loaning out an immutable pointer to these + // contents. + unsafe { &*self.ptr() } + } + + // Non-inlined part of `drop`. Just invokes the destructor. + #[inline(never)] + unsafe fn drop_slow(&mut self) { + let _ = Box::from_raw(self.ptr()); + } + + /// Test pointer equality between the two Arcs, i.e. they must be the _same_ + /// allocation + #[inline] + pub(crate) fn ptr_eq(this: &Self, other: &Self) -> bool { + std::ptr::addr_eq(this.ptr(), other.ptr()) + } + + pub(crate) fn ptr(&self) -> *mut ArcInner { + self.p.as_ptr() + } +} + +impl Clone for Arc { + #[inline] + fn clone(&self) -> Self { + // Using a relaxed ordering is alright here, as knowledge of the + // original reference prevents other threads from erroneously deleting + // the object. + // + // As explained in the [Boost documentation][1], Increasing the + // reference counter can always be done with memory_order_relaxed: New + // references to an object can only be formed from an existing + // reference, and passing an existing reference from one thread to + // another must already provide any required synchronization. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + let old_size = self.inner().count.fetch_add(1, Relaxed); + + // However we need to guard against massive refcounts in case someone + // is `mem::forget`ing Arcs. If we don't do this the count can overflow + // and users will use-after free. We racily saturate to `isize::MAX` on + // the assumption that there aren't ~2 billion threads incrementing + // the reference count at once. This branch will never be taken in + // any realistic program. + // + // We abort because such a program is incredibly degenerate, and we + // don't care to support it. + if old_size > MAX_REFCOUNT { + std::process::abort(); + } + + unsafe { Arc { p: ptr::NonNull::new_unchecked(self.ptr()), phantom: PhantomData } } + } +} + +impl Deref for Arc { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.inner().data + } +} + +impl Arc { + /// Provides mutable access to the contents _if_ the `Arc` is uniquely owned. + #[inline] + pub(crate) fn get_mut(this: &mut Self) -> Option<&mut T> { + if this.is_unique() { + unsafe { + // See make_mut() for documentation of the threadsafety here. + Some(&mut (*this.ptr()).data) + } + } else { + None + } + } + + /// Whether or not the `Arc` is uniquely owned (is the refcount 1?). + pub(crate) fn is_unique(&self) -> bool { + // See the extensive discussion in [1] for why this needs to be Acquire. + // + // [1] https://github.com/servo/servo/issues/21186 + self.inner().count.load(Acquire) == 1 + } +} + +impl Drop for Arc { + #[inline] + fn drop(&mut self) { + // Because `fetch_sub` is already atomic, we do not need to synchronize + // with other threads unless we are going to delete the object. + if self.inner().count.fetch_sub(1, Release) != 1 { + return; + } + + // FIXME(bholley): Use the updated comment when [2] is merged. + // + // This load is needed to prevent reordering of use of the data and + // deletion of the data. Because it is marked `Release`, the decreasing + // of the reference count synchronizes with this `Acquire` load. This + // means that use of the data happens before decreasing the reference + // count, which happens before this load, which happens before the + // deletion of the data. + // + // As explained in the [Boost documentation][1], + // + // > It is important to enforce any possible access to the object in one + // > thread (through an existing reference) to *happen before* deleting + // > the object in a different thread. This is achieved by a "release" + // > operation after dropping a reference (any access to the object + // > through this reference must obviously happened before), and an + // > "acquire" operation before deleting the object. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + // [2]: https://github.com/rust-lang/rust/pull/41714 + self.inner().count.load(Acquire); + + unsafe { + self.drop_slow(); + } + } +} + +impl PartialEq for Arc { + fn eq(&self, other: &Arc) -> bool { + Self::ptr_eq(self, other) || *(*self) == *(*other) + } + + fn ne(&self, other: &Arc) -> bool { + !Self::ptr_eq(self, other) && *(*self) != *(*other) + } +} + +impl PartialOrd for Arc { + fn partial_cmp(&self, other: &Arc) -> Option { + (**self).partial_cmp(&**other) + } + + fn lt(&self, other: &Arc) -> bool { + *(*self) < *(*other) + } + + fn le(&self, other: &Arc) -> bool { + *(*self) <= *(*other) + } + + fn gt(&self, other: &Arc) -> bool { + *(*self) > *(*other) + } + + fn ge(&self, other: &Arc) -> bool { + *(*self) >= *(*other) + } +} + +impl Ord for Arc { + fn cmp(&self, other: &Arc) -> Ordering { + (**self).cmp(&**other) + } +} + +impl Eq for Arc {} + +impl Hash for Arc { + fn hash(&self, state: &mut H) { + (**self).hash(state) + } +} + +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd)] +#[repr(C)] +pub(crate) struct HeaderSlice { + pub(crate) header: H, + length: usize, + slice: T, +} + +impl HeaderSlice { + pub(crate) fn slice(&self) -> &[T] { + &self.slice + } +} + +impl Deref for HeaderSlice { + type Target = HeaderSlice; + + fn deref(&self) -> &Self::Target { + let len = self.length; + let fake_slice: *const [T] = ptr::slice_from_raw_parts(self as *const _ as *const T, len); + unsafe { &*(fake_slice as *const HeaderSlice) } + } +} + +/// A "thin" `Arc` containing dynamically sized data +/// +/// This is functionally equivalent to `Arc<(H, [T])>` +/// +/// When you create an `Arc` containing a dynamically sized type +/// like `HeaderSlice`, the `Arc` is represented on the stack +/// as a "fat pointer", where the length of the slice is stored +/// alongside the `Arc`'s pointer. In some situations you may wish to +/// have a thin pointer instead, perhaps for FFI compatibility +/// or space efficiency. +/// +/// Note that we use `[T; 0]` in order to have the right alignment for `T`. +/// +/// `ThinArc` solves this by storing the length in the allocation itself, +/// via `HeaderSlice`. +#[repr(transparent)] +pub(crate) struct ThinArc { + ptr: ptr::NonNull>>, + phantom: PhantomData<(H, T)>, +} + +unsafe impl Send for ThinArc {} +unsafe impl Sync for ThinArc {} + +// Synthesize a fat pointer from a thin pointer. +fn thin_to_thick( + thin: *mut ArcInner>, +) -> *mut ArcInner> { + let len = unsafe { (*thin).data.length }; + let fake_slice: *mut [T] = ptr::slice_from_raw_parts_mut(thin as *mut T, len); + // Transplants metadata. + fake_slice as *mut ArcInner> +} + +impl ThinArc { + /// Temporarily converts |self| into a bonafide Arc and exposes it to the + /// provided callback. The refcount is not modified. + #[inline] + pub(crate) fn with_arc(&self, f: F) -> U + where + F: FnOnce(&Arc>) -> U, + { + // Synthesize transient Arc, which never touches the refcount of the ArcInner. + let transient = unsafe { + ManuallyDrop::new(Arc { + p: ptr::NonNull::new_unchecked(thin_to_thick(self.ptr.as_ptr())), + phantom: PhantomData, + }) + }; + + // Expose the transient Arc to the callback, which may clone it if it wants. + let result = f(&transient); + + // Forward the result. + result + } + + /// Creates a `ThinArc` for a HeaderSlice using the given header struct and + /// iterator to generate the slice. + pub(crate) fn from_header_and_iter(header: H, mut items: I) -> Self + where + I: Iterator + ExactSizeIterator, + { + assert_ne!(mem::size_of::(), 0, "Need to think about ZST"); + + let num_items = items.len(); + + // Offset of the start of the slice in the allocation. + let inner_to_data_offset = offset_of!(ArcInner>, data); + let data_to_slice_offset = offset_of!(HeaderSlice, slice); + let slice_offset = inner_to_data_offset + data_to_slice_offset; + + // Compute the size of the real payload. + let slice_size = mem::size_of::().checked_mul(num_items).expect("size overflows"); + let usable_size = slice_offset.checked_add(slice_size).expect("size overflows"); + + // Round up size to alignment. + let align = mem::align_of::>>(); + let size = usable_size.wrapping_add(align - 1) & !(align - 1); + assert!(size >= usable_size, "size overflows"); + let layout = Layout::from_size_align(size, align).expect("invalid layout"); + + let ptr: *mut ArcInner>; + unsafe { + let buffer = alloc::alloc(layout); + + if buffer.is_null() { + alloc::handle_alloc_error(layout); + } + + // // Synthesize the fat pointer. We do this by claiming we have a direct + // // pointer to a [T], and then changing the type of the borrow. The key + // // point here is that the length portion of the fat pointer applies + // // only to the number of elements in the dynamically-sized portion of + // // the type, so the value will be the same whether it points to a [T] + // // or something else with a [T] as its last member. + // let fake_slice: &mut [T] = slice::from_raw_parts_mut(buffer as *mut T, num_items); + // ptr = fake_slice as *mut [T] as *mut ArcInner>; + ptr = buffer as *mut _; + + let count = atomic::AtomicUsize::new(1); + + // Write the data. + // + // Note that any panics here (i.e. from the iterator) are safe, since + // we'll just leak the uninitialized memory. + ptr::write(ptr::addr_of_mut!((*ptr).count), count); + ptr::write(ptr::addr_of_mut!((*ptr).data.header), header); + ptr::write(ptr::addr_of_mut!((*ptr).data.length), num_items); + if num_items != 0 { + let mut current = ptr::addr_of_mut!((*ptr).data.slice) as *mut T; + debug_assert_eq!(current as usize - buffer as usize, slice_offset); + for _ in 0..num_items { + ptr::write( + current, + items.next().expect("ExactSizeIterator over-reported length"), + ); + current = current.offset(1); + } + assert!(items.next().is_none(), "ExactSizeIterator under-reported length"); + + // We should have consumed the buffer exactly. + debug_assert_eq!(current as *mut u8, buffer.add(usable_size)); + } + assert!(items.next().is_none(), "ExactSizeIterator under-reported length"); + } + + ThinArc { ptr: unsafe { ptr::NonNull::new_unchecked(ptr) }, phantom: PhantomData } + } +} + +impl Deref for ThinArc { + type Target = HeaderSlice; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &(*thin_to_thick(self.ptr.as_ptr())).data } + } +} + +impl Clone for ThinArc { + #[inline] + fn clone(&self) -> Self { + ThinArc::with_arc(self, |a| Arc::into_thin(a.clone())) + } +} + +impl Drop for ThinArc { + #[inline] + fn drop(&mut self) { + let _ = Arc::from_thin(ThinArc { ptr: self.ptr, phantom: PhantomData }); + } +} + +impl Arc> { + /// Converts an `Arc` into a `ThinArc`. This consumes the `Arc`, so the refcount + /// is not modified. + #[inline] + pub(crate) fn into_thin(a: Self) -> ThinArc { + assert_eq!(a.length, a.slice.len(), "Length needs to be correct for ThinArc to work"); + let fat_ptr: *mut ArcInner> = a.ptr(); + mem::forget(a); + let thin_ptr = fat_ptr as *mut [usize] as *mut usize; + ThinArc { + ptr: unsafe { + ptr::NonNull::new_unchecked(thin_ptr as *mut ArcInner>) + }, + phantom: PhantomData, + } + } + + /// Converts a `ThinArc` into an `Arc`. This consumes the `ThinArc`, so the refcount + /// is not modified. + #[inline] + pub(crate) fn from_thin(a: ThinArc) -> Self { + let ptr = thin_to_thick(a.ptr.as_ptr()); + mem::forget(a); + unsafe { Arc { p: ptr::NonNull::new_unchecked(ptr), phantom: PhantomData } } + } +} + +impl PartialEq for ThinArc { + #[inline] + fn eq(&self, other: &ThinArc) -> bool { + **self == **other + } +} + +impl Eq for ThinArc {} + +impl Hash for ThinArc { + fn hash(&self, state: &mut HSR) { + (**self).hash(state) + } +} diff --git a/third_party/crates/rowan-0.16.1/src/ast.rs b/third_party/crates/rowan-0.16.1/src/ast.rs new file mode 100644 index 0000000..e142395 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/ast.rs @@ -0,0 +1,287 @@ +//! Working with abstract syntax trees. +//! +//! In rowan, syntax trees are transient objects. That means that we create +//! trees when we need them, and tear them down to save memory. In this +//! architecture, hanging on to a particular syntax node for a long time is +//! ill-advisable, as that keeps the whole tree resident. +//! +//! Instead, we provide a [`SyntaxNodePtr`] type, which stores information about +//! the _location_ of a particular syntax node in a tree. It's a small type +//! which can be cheaply stored, and which can be resolved to a real +//! [`SyntaxNode`] when necessary. +//! +//! We also provide an [`AstNode`] trait for typed AST wrapper APIs over rowan +//! nodes. + +use std::{ + fmt, + hash::{Hash, Hasher}, + iter::successors, + marker::PhantomData, +}; + +use crate::{Language, SyntaxNode, SyntaxNodeChildren, TextRange}; + +/// The main trait to go from untyped [`SyntaxNode`] to a typed AST. The +/// conversion itself has zero runtime cost: AST and syntax nodes have exactly +/// the same representation: a pointer to the tree root and a pointer to the +/// node itself. +pub trait AstNode { + type Language: Language; + + fn can_cast(kind: ::Kind) -> bool + where + Self: Sized; + + fn cast(node: SyntaxNode) -> Option + where + Self: Sized; + + fn syntax(&self) -> &SyntaxNode; + + fn clone_for_update(&self) -> Self + where + Self: Sized, + { + Self::cast(self.syntax().clone_for_update()).unwrap() + } + + fn clone_subtree(&self) -> Self + where + Self: Sized, + { + Self::cast(self.syntax().clone_subtree()).unwrap() + } +} + +/// A "pointer" to a [`SyntaxNode`], via location in the source code. +/// +/// ## Note +/// Since the location is source code dependent, this must not be used +/// with mutable syntax trees. Any changes made in such trees causes +/// the pointed node's source location to change, invalidating the pointer. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct SyntaxNodePtr { + kind: L::Kind, + range: TextRange, +} + +impl SyntaxNodePtr { + /// Returns a [`SyntaxNodePtr`] for the node. + /// + /// Panics if the provided node is mutable + pub fn new(node: &SyntaxNode) -> Self { + assert!(!node.is_mutable(), "tree is mutable"); + Self { kind: node.kind(), range: node.text_range() } + } + + /// Like [`Self::try_to_node`] but panics instead of returning `None` on + /// failure. + pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode { + self.try_to_node(root).unwrap_or_else(|| panic!("can't resolve {self:?} with {root:?}")) + } + + /// "Dereferences" the pointer to get the [`SyntaxNode`] it points to. + /// + /// Returns `None` if the node is not found, so make sure that the `root` + /// syntax tree is equivalent to (i.e. is build from the same text from) the + /// tree which was originally used to get this [`SyntaxNodePtr`]. + /// + /// Also returns `None` if `root` is not actually a root (i.e. it has a + /// parent). + /// + /// NOTE: If this function is called on a mutable tree, it will panic + /// + /// The complexity is linear in the depth of the tree and logarithmic in + /// tree width. As most trees are shallow, thinking about this as + /// `O(log(N))` in the size of the tree is not too wrong! + pub fn try_to_node(&self, root: &SyntaxNode) -> Option> { + assert!(!root.is_mutable(), "tree is mutable"); + if root.parent().is_some() { + return None; + } + successors(Some(root.clone()), |node| node.child_or_token_at_range(self.range)?.into_node()) + .find(|it| it.text_range() == self.range && it.kind() == self.kind) + } + + /// Casts this to an [`AstPtr`] to the given node type if possible. + pub fn cast>(self) -> Option> { + if !N::can_cast(self.kind) { + return None; + } + Some(AstPtr { raw: self }) + } + + /// Returns the kind of the syntax node this points to. + pub fn kind(&self) -> L::Kind { + self.kind + } + + /// Returns the range of the syntax node this points to. + pub fn text_range(&self) -> TextRange { + self.range + } +} + +/// Like [`SyntaxNodePtr`], but remembers the type of node. +/// +/// ## Note +/// As with [`SyntaxNodePtr`], this must not be used on mutable +/// syntax trees, since any mutation can cause the pointed node's +/// source location to change, invalidating the pointer +pub struct AstPtr { + raw: SyntaxNodePtr, +} + +impl AstPtr { + /// Returns an [`AstPtr`] for the node. + /// + /// Panics if the provided node is mutable + pub fn new(node: &N) -> Self { + // The above mentioned panic is handled by SyntaxNodePtr + Self { raw: SyntaxNodePtr::new(node.syntax()) } + } + + /// Like `Self::try_to_node` but panics on failure. + pub fn to_node(&self, root: &SyntaxNode) -> N { + self.try_to_node(root).unwrap_or_else(|| panic!("can't resolve {self:?} with {root:?}")) + } + + /// Given the root node containing the node `n` that `self` is a pointer to, + /// returns `n` if possible. Panics if `root` is mutable. See [`SyntaxNodePtr::try_to_node`]. + pub fn try_to_node(&self, root: &SyntaxNode) -> Option { + // The above mentioned panic is handled by SyntaxNodePtr + N::cast(self.raw.try_to_node(root)?) + } + + /// Returns the underlying [`SyntaxNodePtr`]. + pub fn syntax_node_ptr(&self) -> SyntaxNodePtr { + self.raw.clone() + } + + /// Casts this to an [`AstPtr`] to the given node type if possible. + pub fn cast>(self) -> Option> { + if !U::can_cast(self.raw.kind) { + return None; + } + Some(AstPtr { raw: self.raw }) + } +} + +impl fmt::Debug for AstPtr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("AstPtr").field("raw", &self.raw).finish() + } +} + +impl Clone for AstPtr { + fn clone(&self) -> Self { + Self { raw: self.raw.clone() } + } +} + +impl PartialEq for AstPtr { + fn eq(&self, other: &AstPtr) -> bool { + self.raw == other.raw + } +} + +impl Eq for AstPtr {} + +impl Hash for AstPtr { + fn hash(&self, state: &mut H) { + self.raw.hash(state) + } +} + +impl From> for SyntaxNodePtr { + fn from(ptr: AstPtr) -> SyntaxNodePtr { + ptr.raw + } +} + +#[derive(Debug, Clone)] +pub struct AstChildren { + inner: SyntaxNodeChildren, + ph: PhantomData, +} + +impl AstChildren { + fn new(parent: &SyntaxNode) -> Self { + AstChildren { inner: parent.children(), ph: PhantomData } + } +} + +impl Iterator for AstChildren { + type Item = N; + fn next(&mut self) -> Option { + self.inner.find_map(N::cast) + } +} + +pub mod support { + use super::{AstChildren, AstNode}; + use crate::{Language, SyntaxNode, SyntaxToken}; + + pub fn child(parent: &SyntaxNode) -> Option { + parent.children().find_map(N::cast) + } + + pub fn children(parent: &SyntaxNode) -> AstChildren { + AstChildren::new(parent) + } + + pub fn token(parent: &SyntaxNode, kind: L::Kind) -> Option> { + parent.children_with_tokens().filter_map(|it| it.into_token()).find(|it| it.kind() == kind) + } +} + +#[cfg(test)] +mod tests { + use crate::{GreenNodeBuilder, Language, SyntaxKind, SyntaxNode}; + + use super::SyntaxNodePtr; + + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + struct TestLanguage; + impl Language for TestLanguage { + type Kind = SyntaxKind; + + fn kind_from_raw(raw: SyntaxKind) -> Self::Kind { + raw + } + + fn kind_to_raw(kind: Self::Kind) -> SyntaxKind { + kind + } + } + + fn build_immut_tree() -> SyntaxNode { + // Creates a single-node tree + let mut builder = GreenNodeBuilder::new(); + builder.start_node(SyntaxKind(0)); + builder.finish_node(); + + SyntaxNode::::new_root(builder.finish()) + } + + #[test] + #[should_panic = "tree is mutable"] + fn ensure_mut_panic_on_create() { + // Make a mutable version + let tree = build_immut_tree().clone_for_update(); + + SyntaxNodePtr::new(&tree); + } + + #[test] + #[should_panic = "tree is mutable"] + fn ensure_mut_panic_on_deref() { + let tree = build_immut_tree(); + let tree_mut = tree.clone_for_update(); + + // Create on immutable, convert on mutable + let syn_ptr = SyntaxNodePtr::new(&tree); + syn_ptr.to_node(&tree_mut); + } +} diff --git a/third_party/crates/rowan-0.16.1/src/cow_mut.rs b/third_party/crates/rowan-0.16.1/src/cow_mut.rs new file mode 100644 index 0000000..c50e25b --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/cow_mut.rs @@ -0,0 +1,30 @@ +#[derive(Debug)] +pub(crate) enum CowMut<'a, T> { + Owned(T), + Borrowed(&'a mut T), +} + +impl std::ops::Deref for CowMut<'_, T> { + type Target = T; + fn deref(&self) -> &T { + match self { + CowMut::Owned(it) => it, + CowMut::Borrowed(it) => *it, + } + } +} + +impl std::ops::DerefMut for CowMut<'_, T> { + fn deref_mut(&mut self) -> &mut T { + match self { + CowMut::Owned(it) => it, + CowMut::Borrowed(it) => *it, + } + } +} + +impl Default for CowMut<'_, T> { + fn default() -> Self { + CowMut::Owned(T::default()) + } +} diff --git a/third_party/crates/rowan-0.16.1/src/cursor.rs b/third_party/crates/rowan-0.16.1/src/cursor.rs new file mode 100644 index 0000000..cb6ceeb --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/cursor.rs @@ -0,0 +1,1592 @@ +//! Implementation of the cursors -- API for convenient access to syntax trees. +//! +//! Functional programmers will recognize that this module implements a zipper +//! for a purely functional (green) tree. +//! +//! A cursor node (`SyntaxNode`) points to a `GreenNode` and a parent +//! `SyntaxNode`. This allows cursor to provide iteration over both ancestors +//! and descendants, as well as a cheep access to absolute offset of the node in +//! file. +//! +//! By default `SyntaxNode`s are immutable, but you can get a mutable copy of +//! the tree by calling `clone_for_update`. Mutation is based on interior +//! mutability and doesn't need `&mut`. You can have two `SyntaxNode`s pointing +//! at different parts of the same tree; mutations via the first node will be +//! reflected in the other. + +// Implementation notes: +// +// The implementation is utterly and horribly unsafe. This whole module is an +// unsafety boundary. It is believed that the API here is, in principle, sound, +// but the implementation might have bugs. +// +// The core type is `NodeData` -- a heap-allocated reference counted object, +// which points to a green node or a green token, and to the parent `NodeData`. +// Publicly-exposed `SyntaxNode` and `SyntaxToken` own a reference to +// `NodeData`. +// +// `NodeData`s are transient, and are created and destroyed during tree +// traversals. In general, only currently referenced nodes and their ancestors +// are alive at any given moment. +// +// More specifically, `NodeData`'s ref count is equal to the number of +// outstanding `SyntaxNode` and `SyntaxToken` plus the number of children with +// non-zero ref counts. For example, if the user has only a single `SyntaxNode` +// pointing somewhere in the middle of the tree, then all `NodeData` on the path +// from that point towards the root have ref count equal to one. +// +// `NodeData` which doesn't have a parent (is a root) owns the corresponding +// green node or token, and is responsible for freeing it. +// +// That's mostly it for the immutable subset of the API. Mutation is fun though, +// you'll like it! +// +// Mutability is a run-time property of a tree of `NodeData`. The whole tree is +// either mutable or immutable. `clone_for_update` clones the whole tree of +// `NodeData`s, making it mutable (note that the green tree is re-used). +// +// If the tree is mutable, then all live `NodeData` are additionally liked to +// each other via intrusive liked lists. Specifically, there are two pointers to +// siblings, as well as a pointer to the first child. Note that only live nodes +// are considered. If the user only has `SyntaxNode`s for the first and last +// children of some particular node, then their `NodeData` will point at each +// other. +// +// The links are used to propagate mutations across the tree. Specifically, each +// `NodeData` remembers it's index in parent. When the node is detached from or +// attached to the tree, we need to adjust the indices of all subsequent +// siblings. That's what makes the `for c in node.children() { c.detach() }` +// pattern work despite the apparent iterator invalidation. +// +// This code is encapsulated into the sorted linked list (`sll`) module. +// +// The actual mutation consist of functionally "mutating" (creating a +// structurally shared copy) the green node, and then re-spinning the tree. This +// is a delicate process: `NodeData` point directly to the green nodes, so we +// must make sure that those nodes don't move. Additionally, during mutation a +// node might become or might stop being a root, so we must take care to not +// double free / leak its green node. +// +// Because we can change green nodes using only shared references, handing out +// references into green nodes in the public API would be unsound. We don't do +// that, but we do use such references internally a lot. Additionally, for +// tokens the underlying green token actually is immutable, so we can, and do +// return `&str`. +// +// Invariants [must not leak outside of the module]: +// - Mutability is the property of the whole tree. Intermixing elements that +// differ in mutability is not allowed. +// - Mutability property is persistent. +// - References to the green elements' data are not exposed into public API +// when the tree is mutable. +// - TBD + +use std::{ + borrow::Cow, + cell::Cell, + fmt, + hash::{Hash, Hasher}, + iter, + mem::{self, ManuallyDrop}, + ops::Range, + ptr, slice, +}; + +use countme::Count; + +use crate::{ + green::{GreenChild, GreenElementRef, GreenNodeData, GreenTokenData, SyntaxKind}, + sll, + utility_types::Delta, + Direction, GreenNode, GreenToken, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, + WalkEvent, +}; + +enum Green { + Node { ptr: Cell> }, + Token { ptr: ptr::NonNull }, +} + +struct _SyntaxElement; + +struct NodeData { + _c: Count<_SyntaxElement>, + + rc: Cell, + parent: Cell>>, + index: Cell, + green: Green, + + /// Invariant: never changes after NodeData is created. + mutable: bool, + /// Absolute offset for immutable nodes, unused for mutable nodes. + offset: TextSize, + // The following links only have meaning when `mutable` is true. + first: Cell<*const NodeData>, + /// Invariant: never null if mutable. + next: Cell<*const NodeData>, + /// Invariant: never null if mutable. + prev: Cell<*const NodeData>, +} + +unsafe impl sll::Elem for NodeData { + fn prev(&self) -> &Cell<*const Self> { + &self.prev + } + fn next(&self) -> &Cell<*const Self> { + &self.next + } + fn key(&self) -> &Cell { + &self.index + } +} + +pub type SyntaxElement = NodeOrToken; + +pub struct SyntaxNode { + ptr: ptr::NonNull, +} + +impl Clone for SyntaxNode { + #[inline] + fn clone(&self) -> Self { + self.data().inc_rc(); + SyntaxNode { ptr: self.ptr } + } +} + +impl Drop for SyntaxNode { + #[inline] + fn drop(&mut self) { + if self.data().dec_rc() { + unsafe { free(self.ptr) } + } + } +} + +#[derive(Debug)] +pub struct SyntaxToken { + ptr: ptr::NonNull, +} + +impl Clone for SyntaxToken { + #[inline] + fn clone(&self) -> Self { + self.data().inc_rc(); + SyntaxToken { ptr: self.ptr } + } +} + +impl Drop for SyntaxToken { + #[inline] + fn drop(&mut self) { + if self.data().dec_rc() { + unsafe { free(self.ptr) } + } + } +} + +#[inline(never)] +unsafe fn free(mut data: ptr::NonNull) { + loop { + debug_assert_eq!(data.as_ref().rc.get(), 0); + debug_assert!(data.as_ref().first.get().is_null()); + let node = Box::from_raw(data.as_ptr()); + match node.parent.take() { + Some(parent) => { + debug_assert!(parent.as_ref().rc.get() > 0); + if node.mutable { + sll::unlink(&parent.as_ref().first, &*node) + } + if parent.as_ref().dec_rc() { + data = parent; + } else { + break; + } + } + None => { + match &node.green { + Green::Node { ptr } => { + let _ = GreenNode::from_raw(ptr.get()); + } + Green::Token { ptr } => { + let _ = GreenToken::from_raw(*ptr); + } + } + break; + } + } + } +} + +impl NodeData { + #[inline] + fn new( + parent: Option, + index: u32, + offset: TextSize, + green: Green, + mutable: bool, + ) -> ptr::NonNull { + let parent = ManuallyDrop::new(parent); + let res = NodeData { + _c: Count::new(), + rc: Cell::new(1), + parent: Cell::new(parent.as_ref().map(|it| it.ptr)), + index: Cell::new(index), + green, + + mutable, + offset, + first: Cell::new(ptr::null()), + next: Cell::new(ptr::null()), + prev: Cell::new(ptr::null()), + }; + unsafe { + if mutable { + let res_ptr: *const NodeData = &res; + match sll::init((*res_ptr).parent().map(|it| &it.first), res_ptr.as_ref().unwrap()) + { + sll::AddToSllResult::AlreadyInSll(node) => { + if cfg!(debug_assertions) { + assert_eq!((*node).index(), (*res_ptr).index()); + match ((*node).green(), (*res_ptr).green()) { + (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => { + assert!(ptr::eq(lhs, rhs)) + } + (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => { + assert!(ptr::eq(lhs, rhs)) + } + it => { + panic!("node/token confusion: {:?}", it) + } + } + } + + ManuallyDrop::into_inner(parent); + let res = node as *mut NodeData; + (*res).inc_rc(); + return ptr::NonNull::new_unchecked(res); + } + it => { + let res = Box::into_raw(Box::new(res)); + it.add_to_sll(res); + return ptr::NonNull::new_unchecked(res); + } + } + } + ptr::NonNull::new_unchecked(Box::into_raw(Box::new(res))) + } + } + + #[inline] + fn inc_rc(&self) { + let rc = match self.rc.get().checked_add(1) { + Some(it) => it, + None => std::process::abort(), + }; + self.rc.set(rc) + } + + #[inline] + fn dec_rc(&self) -> bool { + let rc = self.rc.get() - 1; + self.rc.set(rc); + rc == 0 + } + + #[inline] + fn key(&self) -> (ptr::NonNull<()>, TextSize) { + let ptr = match &self.green { + Green::Node { ptr } => ptr.get().cast(), + Green::Token { ptr } => ptr.cast(), + }; + (ptr, self.offset()) + } + + #[inline] + fn parent_node(&self) -> Option { + let parent = self.parent()?; + debug_assert!(matches!(parent.green, Green::Node { .. })); + parent.inc_rc(); + Some(SyntaxNode { ptr: ptr::NonNull::from(parent) }) + } + + #[inline] + fn parent(&self) -> Option<&NodeData> { + self.parent.get().map(|it| unsafe { &*it.as_ptr() }) + } + + #[inline] + fn green(&self) -> GreenElementRef<'_> { + match &self.green { + Green::Node { ptr } => GreenElementRef::Node(unsafe { &*ptr.get().as_ptr() }), + Green::Token { ptr } => GreenElementRef::Token(unsafe { &*ptr.as_ref() }), + } + } + #[inline] + fn green_siblings(&self) -> slice::Iter { + match &self.parent().map(|it| &it.green) { + Some(Green::Node { ptr }) => unsafe { &*ptr.get().as_ptr() }.children().raw, + Some(Green::Token { .. }) => { + debug_assert!(false); + [].iter() + } + None => [].iter(), + } + } + #[inline] + fn index(&self) -> u32 { + self.index.get() + } + + #[inline] + fn offset(&self) -> TextSize { + if self.mutable { + self.offset_mut() + } else { + self.offset + } + } + + #[cold] + fn offset_mut(&self) -> TextSize { + let mut res = TextSize::from(0); + + let mut node = self; + while let Some(parent) = node.parent() { + let green = parent.green().into_node().unwrap(); + res += green.children().raw.nth(node.index() as usize).unwrap().rel_offset(); + node = parent; + } + + res + } + + #[inline] + fn text_range(&self) -> TextRange { + let offset = self.offset(); + let len = self.green().text_len(); + TextRange::at(offset, len) + } + + #[inline] + fn kind(&self) -> SyntaxKind { + self.green().kind() + } + + fn next_sibling(&self) -> Option { + let siblings = self.green_siblings().enumerate(); + let index = self.index() as usize; + + siblings.skip(index + 1).find_map(|(index, child)| { + child.as_ref().into_node().and_then(|green| { + let parent = self.parent_node()?; + let offset = parent.offset() + child.rel_offset(); + Some(SyntaxNode::new_child(green, parent, index as u32, offset)) + }) + }) + } + + fn next_sibling_by_kind(&self, matcher: &impl Fn(SyntaxKind) -> bool) -> Option { + let siblings = self.green_siblings().enumerate(); + let index = self.index() as usize; + + siblings.skip(index + 1).find_map(|(index, child)| { + if !matcher(child.as_ref().kind()) { + return None; + } + child.as_ref().into_node().and_then(|green| { + let parent = self.parent_node()?; + let offset = parent.offset() + child.rel_offset(); + Some(SyntaxNode::new_child(green, parent, index as u32, offset)) + }) + }) + } + + fn prev_sibling(&self) -> Option { + let rev_siblings = self.green_siblings().enumerate().rev(); + let index = rev_siblings.len().checked_sub(self.index() as usize)?; + + rev_siblings.skip(index).find_map(|(index, child)| { + child.as_ref().into_node().and_then(|green| { + let parent = self.parent_node()?; + let offset = parent.offset() + child.rel_offset(); + Some(SyntaxNode::new_child(green, parent, index as u32, offset)) + }) + }) + } + + fn next_sibling_or_token(&self) -> Option { + let mut siblings = self.green_siblings().enumerate(); + let index = self.index() as usize + 1; + + siblings.nth(index).and_then(|(index, child)| { + let parent = self.parent_node()?; + let offset = parent.offset() + child.rel_offset(); + Some(SyntaxElement::new(child.as_ref(), parent, index as u32, offset)) + }) + } + + fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option { + let siblings = self.green_siblings().enumerate(); + let index = self.index() as usize; + + siblings.skip(index + 1).find_map(|(index, child)| { + if !matcher(child.as_ref().kind()) { + return None; + } + let parent = self.parent_node()?; + let offset = parent.offset() + child.rel_offset(); + Some(SyntaxElement::new(child.as_ref(), parent, index as u32, offset)) + }) + } + + fn prev_sibling_or_token(&self) -> Option { + let mut siblings = self.green_siblings().enumerate(); + let index = self.index().checked_sub(1)? as usize; + + siblings.nth(index).and_then(|(index, child)| { + let parent = self.parent_node()?; + let offset = parent.offset() + child.rel_offset(); + Some(SyntaxElement::new(child.as_ref(), parent, index as u32, offset)) + }) + } + + fn detach(&self) { + assert!(self.mutable); + assert!(self.rc.get() > 0); + let parent_ptr = match self.parent.take() { + Some(parent) => parent, + None => return, + }; + + sll::adjust(self, self.index() + 1, Delta::Sub(1)); + let parent = unsafe { parent_ptr.as_ref() }; + sll::unlink(&parent.first, self); + + // Add strong ref to green + match self.green().to_owned() { + NodeOrToken::Node(it) => { + GreenNode::into_raw(it); + } + NodeOrToken::Token(it) => { + GreenToken::into_raw(it); + } + } + + match parent.green() { + NodeOrToken::Node(green) => { + let green = green.remove_child(self.index() as usize); + unsafe { parent.respine(green) } + } + NodeOrToken::Token(_) => unreachable!(), + } + + if parent.dec_rc() { + unsafe { free(parent_ptr) } + } + } + fn attach_child(&self, index: usize, child: &NodeData) { + assert!(self.mutable && child.mutable && child.parent().is_none()); + assert!(self.rc.get() > 0 && child.rc.get() > 0); + + child.index.set(index as u32); + child.parent.set(Some(self.into())); + self.inc_rc(); + + if !self.first.get().is_null() { + sll::adjust(unsafe { &*self.first.get() }, index as u32, Delta::Add(1)); + } + + match sll::link(&self.first, child) { + sll::AddToSllResult::AlreadyInSll(_) => { + panic!("Child already in sorted linked list") + } + it => it.add_to_sll(child), + } + + match self.green() { + NodeOrToken::Node(green) => { + // Child is root, so it owns the green node. Steal it! + let child_green = match &child.green { + Green::Node { ptr } => unsafe { GreenNode::from_raw(ptr.get()).into() }, + Green::Token { ptr } => unsafe { GreenToken::from_raw(*ptr).into() }, + }; + + let green = green.insert_child(index, child_green); + unsafe { self.respine(green) }; + } + NodeOrToken::Token(_) => unreachable!(), + } + } + unsafe fn respine(&self, mut new_green: GreenNode) { + let mut node = self; + loop { + let old_green = match &node.green { + Green::Node { ptr } => ptr.replace(ptr::NonNull::from(&*new_green)), + Green::Token { .. } => unreachable!(), + }; + match node.parent() { + Some(parent) => match parent.green() { + NodeOrToken::Node(parent_green) => { + new_green = + parent_green.replace_child(node.index() as usize, new_green.into()); + node = parent; + } + _ => unreachable!(), + }, + None => { + mem::forget(new_green); + let _ = GreenNode::from_raw(old_green); + break; + } + } + } + } +} + +impl SyntaxNode { + pub fn new_root(green: GreenNode) -> SyntaxNode { + let green = GreenNode::into_raw(green); + let green = Green::Node { ptr: Cell::new(green) }; + SyntaxNode { ptr: NodeData::new(None, 0, 0.into(), green, false) } + } + + pub fn new_root_mut(green: GreenNode) -> SyntaxNode { + let green = GreenNode::into_raw(green); + let green = Green::Node { ptr: Cell::new(green) }; + SyntaxNode { ptr: NodeData::new(None, 0, 0.into(), green, true) } + } + + fn new_child( + green: &GreenNodeData, + parent: SyntaxNode, + index: u32, + offset: TextSize, + ) -> SyntaxNode { + let mutable = parent.data().mutable; + let green = Green::Node { ptr: Cell::new(green.into()) }; + SyntaxNode { ptr: NodeData::new(Some(parent), index, offset, green, mutable) } + } + + pub fn is_mutable(&self) -> bool { + self.data().mutable + } + + pub fn clone_for_update(&self) -> SyntaxNode { + assert!(!self.data().mutable); + match self.parent() { + Some(parent) => { + let parent = parent.clone_for_update(); + SyntaxNode::new_child(self.green_ref(), parent, self.data().index(), self.offset()) + } + None => SyntaxNode::new_root_mut(self.green_ref().to_owned()), + } + } + + pub fn clone_subtree(&self) -> SyntaxNode { + SyntaxNode::new_root(self.green().into()) + } + + #[inline] + fn data(&self) -> &NodeData { + unsafe { self.ptr.as_ref() } + } + + #[inline] + fn can_take_ptr(&self) -> bool { + self.data().rc.get() == 1 && !self.data().mutable + } + + #[inline] + fn take_ptr(self) -> ptr::NonNull { + assert!(self.can_take_ptr()); + let ret = self.ptr; + // don't change the refcount when self gets dropped + std::mem::forget(self); + ret + } + + pub fn replace_with(&self, replacement: GreenNode) -> GreenNode { + assert_eq!(self.kind(), replacement.kind()); + match &self.parent() { + None => replacement, + Some(parent) => { + let new_parent = parent + .green_ref() + .replace_child(self.data().index() as usize, replacement.into()); + parent.replace_with(new_parent) + } + } + } + + #[inline] + pub fn kind(&self) -> SyntaxKind { + self.data().kind() + } + + #[inline] + fn offset(&self) -> TextSize { + self.data().offset() + } + + #[inline] + pub fn text_range(&self) -> TextRange { + self.data().text_range() + } + + #[inline] + pub fn index(&self) -> usize { + self.data().index() as usize + } + + #[inline] + pub fn text(&self) -> SyntaxText { + SyntaxText::new(self.clone()) + } + + #[inline] + pub fn green(&self) -> Cow<'_, GreenNodeData> { + let green_ref = self.green_ref(); + match self.data().mutable { + false => Cow::Borrowed(green_ref), + true => Cow::Owned(green_ref.to_owned()), + } + } + #[inline] + fn green_ref(&self) -> &GreenNodeData { + self.data().green().into_node().unwrap() + } + + #[inline] + pub fn parent(&self) -> Option { + self.data().parent_node() + } + + #[inline] + pub fn ancestors(&self) -> impl Iterator { + iter::successors(Some(self.clone()), SyntaxNode::parent) + } + + #[inline] + pub fn children(&self) -> SyntaxNodeChildren { + SyntaxNodeChildren::new(self.clone()) + } + + #[inline] + pub fn children_with_tokens(&self) -> SyntaxElementChildren { + SyntaxElementChildren::new(self.clone()) + } + + pub fn first_child(&self) -> Option { + self.green_ref().children().raw.enumerate().find_map(|(index, child)| { + child.as_ref().into_node().map(|green| { + SyntaxNode::new_child( + green, + self.clone(), + index as u32, + self.offset() + child.rel_offset(), + ) + }) + }) + } + + pub fn first_child_by_kind(&self, matcher: &impl Fn(SyntaxKind) -> bool) -> Option { + self.green_ref().children().raw.enumerate().find_map(|(index, child)| { + if !matcher(child.as_ref().kind()) { + return None; + } + child.as_ref().into_node().map(|green| { + SyntaxNode::new_child( + green, + self.clone(), + index as u32, + self.offset() + child.rel_offset(), + ) + }) + }) + } + + pub fn last_child(&self) -> Option { + self.green_ref().children().raw.enumerate().rev().find_map(|(index, child)| { + child.as_ref().into_node().map(|green| { + SyntaxNode::new_child( + green, + self.clone(), + index as u32, + self.offset() + child.rel_offset(), + ) + }) + }) + } + + pub fn first_child_or_token(&self) -> Option { + self.green_ref().children().raw.next().map(|child| { + SyntaxElement::new(child.as_ref(), self.clone(), 0, self.offset() + child.rel_offset()) + }) + } + + pub fn first_child_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option { + self.green_ref().children().raw.enumerate().find_map(|(index, child)| { + if !matcher(child.as_ref().kind()) { + return None; + } + Some(SyntaxElement::new( + child.as_ref(), + self.clone(), + index as u32, + self.offset() + child.rel_offset(), + )) + }) + } + + pub fn last_child_or_token(&self) -> Option { + self.green_ref().children().raw.enumerate().next_back().map(|(index, child)| { + SyntaxElement::new( + child.as_ref(), + self.clone(), + index as u32, + self.offset() + child.rel_offset(), + ) + }) + } + + // if possible (i.e. unshared), consume self and advance it to point to the next sibling + // this way, we can reuse the previously allocated buffer + pub fn to_next_sibling(self) -> Option { + if !self.can_take_ptr() { + // cannot mutate in-place + return self.next_sibling(); + } + + let mut ptr = self.take_ptr(); + let data = unsafe { ptr.as_mut() }; + assert!(data.rc.get() == 1); + + let parent = data.parent_node()?; + let parent_offset = parent.offset(); + let siblings = parent.green_ref().children().raw.enumerate(); + let index = data.index() as usize; + + siblings + .skip(index + 1) + .find_map(|(index, child)| { + child + .as_ref() + .into_node() + .and_then(|green| Some((green, index as u32, child.rel_offset()))) + }) + .and_then(|(green, index, rel_offset)| { + data.index.set(index); + data.offset = parent_offset + rel_offset; + data.green = Green::Node { ptr: Cell::new(green.into()) }; + Some(SyntaxNode { ptr }) + }) + .or_else(|| { + data.dec_rc(); + unsafe { free(ptr) }; + None + }) + } + + pub fn next_sibling(&self) -> Option { + self.data().next_sibling() + } + + pub fn next_sibling_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option { + self.data().next_sibling_by_kind(matcher) + } + + pub fn prev_sibling(&self) -> Option { + self.data().prev_sibling() + } + + pub fn next_sibling_or_token(&self) -> Option { + self.data().next_sibling_or_token() + } + + pub fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option { + self.data().next_sibling_or_token_by_kind(matcher) + } + + pub fn prev_sibling_or_token(&self) -> Option { + self.data().prev_sibling_or_token() + } + + pub fn first_token(&self) -> Option { + self.first_child_or_token()?.first_token() + } + pub fn last_token(&self) -> Option { + self.last_child_or_token()?.last_token() + } + + #[inline] + pub fn siblings(&self, direction: Direction) -> impl Iterator { + iter::successors(Some(self.clone()), move |node| match direction { + Direction::Next => node.next_sibling(), + Direction::Prev => node.prev_sibling(), + }) + } + + #[inline] + pub fn siblings_with_tokens( + &self, + direction: Direction, + ) -> impl Iterator { + let me: SyntaxElement = self.clone().into(); + iter::successors(Some(me), move |el| match direction { + Direction::Next => el.next_sibling_or_token(), + Direction::Prev => el.prev_sibling_or_token(), + }) + } + + #[inline] + pub fn descendants(&self) -> impl Iterator { + self.preorder().filter_map(|event| match event { + WalkEvent::Enter(node) => Some(node), + WalkEvent::Leave(_) => None, + }) + } + + #[inline] + pub fn descendants_with_tokens(&self) -> impl Iterator { + self.preorder_with_tokens().filter_map(|event| match event { + WalkEvent::Enter(it) => Some(it), + WalkEvent::Leave(_) => None, + }) + } + + #[inline] + pub fn preorder(&self) -> Preorder { + Preorder::new(self.clone()) + } + + #[inline] + pub fn preorder_with_tokens(&self) -> PreorderWithTokens { + PreorderWithTokens::new(self.clone()) + } + + pub fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset { + // TODO: this could be faster if we first drill-down to node, and only + // then switch to token search. We should also replace explicit + // recursion with a loop. + let range = self.text_range(); + assert!( + range.start() <= offset && offset <= range.end(), + "Bad offset: range {:?} offset {:?}", + range, + offset + ); + if range.is_empty() { + return TokenAtOffset::None; + } + + let mut children = self.children_with_tokens().filter(|child| { + let child_range = child.text_range(); + !child_range.is_empty() + && (child_range.start() <= offset && offset <= child_range.end()) + }); + + let left = children.next().unwrap(); + let right = children.next(); + assert!(children.next().is_none()); + + if let Some(right) = right { + match (left.token_at_offset(offset), right.token_at_offset(offset)) { + (TokenAtOffset::Single(left), TokenAtOffset::Single(right)) => { + TokenAtOffset::Between(left, right) + } + _ => unreachable!(), + } + } else { + left.token_at_offset(offset) + } + } + + pub fn covering_element(&self, range: TextRange) -> SyntaxElement { + let mut res: SyntaxElement = self.clone().into(); + loop { + assert!( + res.text_range().contains_range(range), + "Bad range: node range {:?}, range {:?}", + res.text_range(), + range, + ); + res = match &res { + NodeOrToken::Token(_) => return res, + NodeOrToken::Node(node) => match node.child_or_token_at_range(range) { + Some(it) => it, + None => return res, + }, + }; + } + } + + pub fn child_or_token_at_range(&self, range: TextRange) -> Option { + let rel_range = range - self.offset(); + self.green_ref().child_at_range(rel_range).map(|(index, rel_offset, green)| { + SyntaxElement::new(green, self.clone(), index as u32, self.offset() + rel_offset) + }) + } + + pub fn splice_children>( + &self, + to_delete: Range, + to_insert: I, + ) { + assert!(self.data().mutable, "immutable tree: {}", self); + for (i, child) in self.children_with_tokens().enumerate() { + if to_delete.contains(&i) { + child.detach(); + } + } + let mut index = to_delete.start; + for child in to_insert { + self.attach_child(index, child); + index += 1; + } + } + + pub fn detach(&self) { + assert!(self.data().mutable, "immutable tree: {}", self); + self.data().detach() + } + + fn attach_child(&self, index: usize, child: SyntaxElement) { + assert!(self.data().mutable, "immutable tree: {}", self); + child.detach(); + let data = match &child { + NodeOrToken::Node(it) => it.data(), + NodeOrToken::Token(it) => it.data(), + }; + self.data().attach_child(index, data) + } +} + +impl SyntaxToken { + fn new( + green: &GreenTokenData, + parent: SyntaxNode, + index: u32, + offset: TextSize, + ) -> SyntaxToken { + let mutable = parent.data().mutable; + let green = Green::Token { ptr: green.into() }; + SyntaxToken { ptr: NodeData::new(Some(parent), index, offset, green, mutable) } + } + + #[inline] + fn data(&self) -> &NodeData { + unsafe { self.ptr.as_ref() } + } + + #[inline] + fn can_take_ptr(&self) -> bool { + self.data().rc.get() == 1 && !self.data().mutable + } + + #[inline] + fn take_ptr(self) -> ptr::NonNull { + assert!(self.can_take_ptr()); + let ret = self.ptr; + // don't change the refcount when self gets dropped + std::mem::forget(self); + ret + } + + pub fn replace_with(&self, replacement: GreenToken) -> GreenNode { + assert_eq!(self.kind(), replacement.kind()); + let parent = self.parent().unwrap(); + let me: u32 = self.data().index(); + + let new_parent = parent.green_ref().replace_child(me as usize, replacement.into()); + parent.replace_with(new_parent) + } + + #[inline] + pub fn kind(&self) -> SyntaxKind { + self.data().kind() + } + + #[inline] + pub fn text_range(&self) -> TextRange { + self.data().text_range() + } + + #[inline] + pub fn index(&self) -> usize { + self.data().index() as usize + } + + #[inline] + pub fn text(&self) -> &str { + match self.data().green().as_token() { + Some(it) => it.text(), + None => { + debug_assert!( + false, + "corrupted tree: a node thinks it is a token: {:?}", + self.data().green().as_node().unwrap().to_string() + ); + "" + } + } + } + + #[inline] + pub fn green(&self) -> &GreenTokenData { + self.data().green().into_token().unwrap() + } + + #[inline] + pub fn parent(&self) -> Option { + self.data().parent_node() + } + + #[inline] + pub fn ancestors(&self) -> impl Iterator { + std::iter::successors(self.parent(), SyntaxNode::parent) + } + + pub fn next_sibling_or_token(&self) -> Option { + self.data().next_sibling_or_token() + } + + pub fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option { + self.data().next_sibling_or_token_by_kind(matcher) + } + + pub fn prev_sibling_or_token(&self) -> Option { + self.data().prev_sibling_or_token() + } + + #[inline] + pub fn siblings_with_tokens( + &self, + direction: Direction, + ) -> impl Iterator { + let me: SyntaxElement = self.clone().into(); + iter::successors(Some(me), move |el| match direction { + Direction::Next => el.next_sibling_or_token(), + Direction::Prev => el.prev_sibling_or_token(), + }) + } + + pub fn next_token(&self) -> Option { + match self.next_sibling_or_token() { + Some(element) => element.first_token(), + None => self + .ancestors() + .find_map(|it| it.next_sibling_or_token()) + .and_then(|element| element.first_token()), + } + } + pub fn prev_token(&self) -> Option { + match self.prev_sibling_or_token() { + Some(element) => element.last_token(), + None => self + .ancestors() + .find_map(|it| it.prev_sibling_or_token()) + .and_then(|element| element.last_token()), + } + } + + pub fn detach(&self) { + assert!(self.data().mutable, "immutable tree: {}", self); + self.data().detach() + } +} + +impl SyntaxElement { + fn new( + element: GreenElementRef<'_>, + parent: SyntaxNode, + index: u32, + offset: TextSize, + ) -> SyntaxElement { + match element { + NodeOrToken::Node(node) => { + SyntaxNode::new_child(node, parent, index as u32, offset).into() + } + NodeOrToken::Token(token) => { + SyntaxToken::new(token, parent, index as u32, offset).into() + } + } + } + + #[inline] + pub fn text_range(&self) -> TextRange { + match self { + NodeOrToken::Node(it) => it.text_range(), + NodeOrToken::Token(it) => it.text_range(), + } + } + + #[inline] + pub fn index(&self) -> usize { + match self { + NodeOrToken::Node(it) => it.index(), + NodeOrToken::Token(it) => it.index(), + } + } + + #[inline] + pub fn kind(&self) -> SyntaxKind { + match self { + NodeOrToken::Node(it) => it.kind(), + NodeOrToken::Token(it) => it.kind(), + } + } + + #[inline] + pub fn parent(&self) -> Option { + match self { + NodeOrToken::Node(it) => it.parent(), + NodeOrToken::Token(it) => it.parent(), + } + } + + #[inline] + pub fn ancestors(&self) -> impl Iterator { + let first = match self { + NodeOrToken::Node(it) => Some(it.clone()), + NodeOrToken::Token(it) => it.parent(), + }; + iter::successors(first, SyntaxNode::parent) + } + + pub fn first_token(&self) -> Option { + match self { + NodeOrToken::Node(it) => it.first_token(), + NodeOrToken::Token(it) => Some(it.clone()), + } + } + pub fn last_token(&self) -> Option { + match self { + NodeOrToken::Node(it) => it.last_token(), + NodeOrToken::Token(it) => Some(it.clone()), + } + } + + pub fn next_sibling_or_token(&self) -> Option { + match self { + NodeOrToken::Node(it) => it.next_sibling_or_token(), + NodeOrToken::Token(it) => it.next_sibling_or_token(), + } + } + + fn can_take_ptr(&self) -> bool { + match self { + NodeOrToken::Node(it) => it.can_take_ptr(), + NodeOrToken::Token(it) => it.can_take_ptr(), + } + } + + fn take_ptr(self) -> ptr::NonNull { + match self { + NodeOrToken::Node(it) => it.take_ptr(), + NodeOrToken::Token(it) => it.take_ptr(), + } + } + + // if possible (i.e. unshared), consume self and advance it to point to the next sibling + // this way, we can reuse the previously allocated buffer + pub fn to_next_sibling_or_token(self) -> Option { + if !self.can_take_ptr() { + // cannot mutate in-place + return self.next_sibling_or_token(); + } + + let mut ptr = self.take_ptr(); + let data = unsafe { ptr.as_mut() }; + + let parent = data.parent_node()?; + let parent_offset = parent.offset(); + let siblings = parent.green_ref().children().raw.enumerate(); + let index = data.index() as usize; + + siblings + .skip(index + 1) + .find_map(|(index, green)| { + data.index.set(index as u32); + data.offset = parent_offset + green.rel_offset(); + + match green.as_ref() { + NodeOrToken::Node(node) => { + data.green = Green::Node { ptr: Cell::new(node.into()) }; + Some(SyntaxElement::Node(SyntaxNode { ptr })) + } + NodeOrToken::Token(token) => { + data.green = Green::Token { ptr: token.into() }; + Some(SyntaxElement::Token(SyntaxToken { ptr })) + } + } + }) + .or_else(|| { + data.dec_rc(); + unsafe { free(ptr) }; + None + }) + } + + pub fn next_sibling_or_token_by_kind( + &self, + matcher: &impl Fn(SyntaxKind) -> bool, + ) -> Option { + match self { + NodeOrToken::Node(it) => it.next_sibling_or_token_by_kind(matcher), + NodeOrToken::Token(it) => it.next_sibling_or_token_by_kind(matcher), + } + } + + pub fn prev_sibling_or_token(&self) -> Option { + match self { + NodeOrToken::Node(it) => it.prev_sibling_or_token(), + NodeOrToken::Token(it) => it.prev_sibling_or_token(), + } + } + + fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset { + assert!(self.text_range().start() <= offset && offset <= self.text_range().end()); + match self { + NodeOrToken::Token(token) => TokenAtOffset::Single(token.clone()), + NodeOrToken::Node(node) => node.token_at_offset(offset), + } + } + + pub fn detach(&self) { + match self { + NodeOrToken::Node(it) => it.detach(), + NodeOrToken::Token(it) => it.detach(), + } + } +} + +// region: impls + +// Identity semantics for hash & eq +impl PartialEq for SyntaxNode { + #[inline] + fn eq(&self, other: &SyntaxNode) -> bool { + self.data().key() == other.data().key() + } +} + +impl Eq for SyntaxNode {} + +impl Hash for SyntaxNode { + #[inline] + fn hash(&self, state: &mut H) { + self.data().key().hash(state); + } +} + +impl fmt::Debug for SyntaxNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SyntaxNode") + .field("kind", &self.kind()) + .field("text_range", &self.text_range()) + .finish() + } +} + +impl fmt::Display for SyntaxNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.preorder_with_tokens() + .filter_map(|event| match event { + WalkEvent::Enter(NodeOrToken::Token(token)) => Some(token), + _ => None, + }) + .try_for_each(|it| fmt::Display::fmt(&it, f)) + } +} + +// Identity semantics for hash & eq +impl PartialEq for SyntaxToken { + #[inline] + fn eq(&self, other: &SyntaxToken) -> bool { + self.data().key() == other.data().key() + } +} + +impl Eq for SyntaxToken {} + +impl Hash for SyntaxToken { + #[inline] + fn hash(&self, state: &mut H) { + self.data().key().hash(state); + } +} + +impl fmt::Display for SyntaxToken { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.text(), f) + } +} + +impl From for SyntaxElement { + #[inline] + fn from(node: SyntaxNode) -> SyntaxElement { + NodeOrToken::Node(node) + } +} + +impl From for SyntaxElement { + #[inline] + fn from(token: SyntaxToken) -> SyntaxElement { + NodeOrToken::Token(token) + } +} + +// endregion + +// region: iterators + +#[derive(Clone, Debug)] +pub struct SyntaxNodeChildren { + parent: SyntaxNode, + next: Option, + next_initialized: bool, +} + +impl SyntaxNodeChildren { + fn new(parent: SyntaxNode) -> SyntaxNodeChildren { + SyntaxNodeChildren { parent, next: None, next_initialized: false } + } + + pub fn by_kind bool>(self, matcher: F) -> SyntaxNodeChildrenByKind { + if !self.next_initialized { + SyntaxNodeChildrenByKind { next: self.parent.first_child_by_kind(&matcher), matcher } + } else { + SyntaxNodeChildrenByKind { + next: self.next.and_then(|node| { + if matcher(node.kind()) { + Some(node) + } else { + node.next_sibling_by_kind(&matcher) + } + }), + matcher, + } + } + } +} + +impl Iterator for SyntaxNodeChildren { + type Item = SyntaxNode; + fn next(&mut self) -> Option { + if !self.next_initialized { + self.next = self.parent.first_child(); + self.next_initialized = true; + } else { + self.next = self.next.take().and_then(|next| next.to_next_sibling()); + } + + self.next.clone() + } +} + +#[derive(Clone, Debug)] +pub struct SyntaxNodeChildrenByKind bool> { + next: Option, + matcher: F, +} + +impl bool> Iterator for SyntaxNodeChildrenByKind { + type Item = SyntaxNode; + fn next(&mut self) -> Option { + self.next.take().map(|next| { + self.next = next.next_sibling_by_kind(&self.matcher); + next + }) + } +} + +#[derive(Clone, Debug)] +pub struct SyntaxElementChildren { + parent: SyntaxNode, + next: Option, + next_initialized: bool, +} + +impl SyntaxElementChildren { + fn new(parent: SyntaxNode) -> SyntaxElementChildren { + SyntaxElementChildren { parent, next: None, next_initialized: false } + } + + pub fn by_kind bool>(self, matcher: F) -> SyntaxElementChildrenByKind { + if !self.next_initialized { + SyntaxElementChildrenByKind { + next: self.parent.first_child_or_token_by_kind(&matcher), + matcher, + } + } else { + SyntaxElementChildrenByKind { + next: self.next.and_then(|node| { + if matcher(node.kind()) { + Some(node) + } else { + node.next_sibling_or_token_by_kind(&matcher) + } + }), + matcher, + } + } + } +} + +impl Iterator for SyntaxElementChildren { + type Item = SyntaxElement; + fn next(&mut self) -> Option { + if !self.next_initialized { + self.next = self.parent.first_child_or_token(); + self.next_initialized = true; + } else { + self.next = self.next.take().and_then(|next| next.to_next_sibling_or_token()); + } + + self.next.clone() + } +} + +#[derive(Clone, Debug)] +pub struct SyntaxElementChildrenByKind bool> { + next: Option, + matcher: F, +} + +impl bool> Iterator for SyntaxElementChildrenByKind { + type Item = SyntaxElement; + fn next(&mut self) -> Option { + self.next.take().map(|next| { + self.next = next.next_sibling_or_token_by_kind(&self.matcher); + next + }) + } +} + +pub struct Preorder { + start: SyntaxNode, + next: Option>, + skip_subtree: bool, +} + +impl Preorder { + fn new(start: SyntaxNode) -> Preorder { + let next = Some(WalkEvent::Enter(start.clone())); + Preorder { start, next, skip_subtree: false } + } + + pub fn skip_subtree(&mut self) { + self.skip_subtree = true; + } + + #[cold] + fn do_skip(&mut self) { + self.next = self.next.take().map(|next| match next { + WalkEvent::Enter(first_child) => WalkEvent::Leave(first_child.parent().unwrap()), + WalkEvent::Leave(parent) => WalkEvent::Leave(parent), + }) + } +} + +impl Iterator for Preorder { + type Item = WalkEvent; + + fn next(&mut self) -> Option> { + if self.skip_subtree { + self.do_skip(); + self.skip_subtree = false; + } + let next = self.next.take(); + self.next = next.as_ref().and_then(|next| { + Some(match next { + WalkEvent::Enter(node) => match node.first_child() { + Some(child) => WalkEvent::Enter(child), + None => WalkEvent::Leave(node.clone()), + }, + WalkEvent::Leave(node) => { + if node == &self.start { + return None; + } + match node.next_sibling() { + Some(sibling) => WalkEvent::Enter(sibling), + None => WalkEvent::Leave(node.parent()?), + } + } + }) + }); + next + } +} + +pub struct PreorderWithTokens { + start: SyntaxElement, + next: Option>, + skip_subtree: bool, +} + +impl PreorderWithTokens { + fn new(start: SyntaxNode) -> PreorderWithTokens { + let next = Some(WalkEvent::Enter(start.clone().into())); + PreorderWithTokens { start: start.into(), next, skip_subtree: false } + } + + pub fn skip_subtree(&mut self) { + self.skip_subtree = true; + } + + #[cold] + fn do_skip(&mut self) { + self.next = self.next.take().map(|next| match next { + WalkEvent::Enter(first_child) => WalkEvent::Leave(first_child.parent().unwrap().into()), + WalkEvent::Leave(parent) => WalkEvent::Leave(parent), + }) + } +} + +impl Iterator for PreorderWithTokens { + type Item = WalkEvent; + + fn next(&mut self) -> Option> { + if self.skip_subtree { + self.do_skip(); + self.skip_subtree = false; + } + let next = self.next.take(); + self.next = next.as_ref().and_then(|next| { + Some(match next { + WalkEvent::Enter(el) => match el { + NodeOrToken::Node(node) => match node.first_child_or_token() { + Some(child) => WalkEvent::Enter(child), + None => WalkEvent::Leave(node.clone().into()), + }, + NodeOrToken::Token(token) => WalkEvent::Leave(token.clone().into()), + }, + WalkEvent::Leave(el) if el == &self.start => return None, + WalkEvent::Leave(el) => match el.next_sibling_or_token() { + Some(sibling) => WalkEvent::Enter(sibling), + None => WalkEvent::Leave(el.parent()?.into()), + }, + }) + }); + next + } +} +// endregion diff --git a/third_party/crates/rowan-0.16.1/src/green.rs b/third_party/crates/rowan-0.16.1/src/green.rs new file mode 100644 index 0000000..e2b5b4a --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/green.rs @@ -0,0 +1,42 @@ +mod node; +mod token; +mod element; +mod builder; +mod node_cache; + +use self::element::GreenElement; + +pub(crate) use self::{element::GreenElementRef, node::GreenChild}; + +pub use self::{ + builder::{Checkpoint, GreenNodeBuilder}, + node::{Children, GreenNode, GreenNodeData}, + node_cache::NodeCache, + token::{GreenToken, GreenTokenData}, +}; + +/// SyntaxKind is a type tag for each token or node. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct SyntaxKind(pub u16); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn assert_send_sync() { + fn f() {} + f::(); + f::(); + f::(); + } + + #[test] + fn test_size_of() { + use std::mem::size_of; + + eprintln!("GreenNode {}", size_of::()); + eprintln!("GreenToken {}", size_of::()); + eprintln!("GreenElement {}", size_of::()); + } +} diff --git a/third_party/crates/rowan-0.16.1/src/green/builder.rs b/third_party/crates/rowan-0.16.1/src/green/builder.rs new file mode 100644 index 0000000..03d66df --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/green/builder.rs @@ -0,0 +1,131 @@ +use std::num::NonZeroUsize; + +use crate::{ + cow_mut::CowMut, + green::{node_cache::NodeCache, GreenElement, GreenNode, SyntaxKind}, + NodeOrToken, +}; + +/// A checkpoint for maybe wrapping a node. See `GreenNodeBuilder::checkpoint` for details. +#[derive(Clone, Copy, Debug)] +pub struct Checkpoint(NonZeroUsize); + +impl Checkpoint { + fn new(inner: usize) -> Self { + Self(NonZeroUsize::new(inner + 1).unwrap()) + } + + fn into_inner(self) -> usize { + self.0.get() - 1 + } +} + +/// A builder for a green tree. +#[derive(Default, Debug)] +pub struct GreenNodeBuilder<'cache> { + cache: CowMut<'cache, NodeCache>, + parents: Vec<(SyntaxKind, usize)>, + children: Vec<(u64, GreenElement)>, +} + +impl GreenNodeBuilder<'_> { + /// Creates new builder. + pub fn new() -> GreenNodeBuilder<'static> { + GreenNodeBuilder::default() + } + + /// Reusing `NodeCache` between different `GreenNodeBuilder`s saves memory. + /// It allows to structurally share underlying trees. + pub fn with_cache(cache: &mut NodeCache) -> GreenNodeBuilder<'_> { + GreenNodeBuilder { + cache: CowMut::Borrowed(cache), + parents: Vec::new(), + children: Vec::new(), + } + } + + /// Adds new token to the current branch. + #[inline] + pub fn token(&mut self, kind: SyntaxKind, text: &str) { + let (hash, token) = self.cache.token(kind, text); + self.children.push((hash, token.into())); + } + + /// Start new node and make it current. + #[inline] + pub fn start_node(&mut self, kind: SyntaxKind) { + let len = self.children.len(); + self.parents.push((kind, len)); + } + + /// Finish current branch and restore previous + /// branch as current. + #[inline] + pub fn finish_node(&mut self) { + let (kind, first_child) = self.parents.pop().unwrap(); + let (hash, node) = self.cache.node(kind, &mut self.children, first_child); + self.children.push((hash, node.into())); + } + + /// Prepare for maybe wrapping the next node. + /// The way wrapping works is that you first of all get a checkpoint, + /// then you place all tokens you want to wrap, and then *maybe* call + /// `start_node_at`. + /// Example: + /// ```rust + /// # use rowan::{GreenNodeBuilder, SyntaxKind}; + /// # const PLUS: SyntaxKind = SyntaxKind(0); + /// # const OPERATION: SyntaxKind = SyntaxKind(1); + /// # struct Parser; + /// # impl Parser { + /// # fn peek(&self) -> Option { None } + /// # fn parse_expr(&mut self) {} + /// # } + /// # let mut builder = GreenNodeBuilder::new(); + /// # let mut parser = Parser; + /// let checkpoint = builder.checkpoint(); + /// parser.parse_expr(); + /// if parser.peek() == Some(PLUS) { + /// // 1 + 2 = Add(1, 2) + /// builder.start_node_at(checkpoint, OPERATION); + /// parser.parse_expr(); + /// builder.finish_node(); + /// } + /// ``` + #[inline] + pub fn checkpoint(&self) -> Checkpoint { + Checkpoint::new(self.children.len()) + } + + /// Wrap the previous branch marked by `checkpoint` in a new branch and + /// make it current. + #[inline] + pub fn start_node_at(&mut self, checkpoint: Checkpoint, kind: SyntaxKind) { + let checkpoint = checkpoint.into_inner(); + assert!( + checkpoint <= self.children.len(), + "checkpoint no longer valid, was finish_node called early?" + ); + + if let Some(&(_, first_child)) = self.parents.last() { + assert!( + checkpoint >= first_child, + "checkpoint no longer valid, was an unmatched start_node_at called?" + ); + } + + self.parents.push((kind, checkpoint)); + } + + /// Complete tree building. Make sure that + /// `start_node_at` and `finish_node` calls + /// are paired! + #[inline] + pub fn finish(mut self) -> GreenNode { + assert_eq!(self.children.len(), 1); + match self.children.pop().unwrap().1 { + NodeOrToken::Node(node) => node, + NodeOrToken::Token(_) => panic!(), + } + } +} diff --git a/third_party/crates/rowan-0.16.1/src/green/element.rs b/third_party/crates/rowan-0.16.1/src/green/element.rs new file mode 100644 index 0000000..2d1ce1f --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/green/element.rs @@ -0,0 +1,89 @@ +use std::borrow::Cow; + +use crate::{ + green::{GreenNode, GreenToken, SyntaxKind}, + GreenNodeData, NodeOrToken, TextSize, +}; + +use super::GreenTokenData; + +pub(super) type GreenElement = NodeOrToken; +pub(crate) type GreenElementRef<'a> = NodeOrToken<&'a GreenNodeData, &'a GreenTokenData>; + +impl From for GreenElement { + #[inline] + fn from(node: GreenNode) -> GreenElement { + NodeOrToken::Node(node) + } +} + +impl<'a> From<&'a GreenNode> for GreenElementRef<'a> { + #[inline] + fn from(node: &'a GreenNode) -> GreenElementRef<'a> { + NodeOrToken::Node(node) + } +} + +impl From for GreenElement { + #[inline] + fn from(token: GreenToken) -> GreenElement { + NodeOrToken::Token(token) + } +} + +impl From> for GreenElement { + #[inline] + fn from(cow: Cow<'_, GreenNodeData>) -> Self { + NodeOrToken::Node(cow.into_owned()) + } +} + +impl<'a> From<&'a GreenToken> for GreenElementRef<'a> { + #[inline] + fn from(token: &'a GreenToken) -> GreenElementRef<'a> { + NodeOrToken::Token(token) + } +} + +impl GreenElementRef<'_> { + pub fn to_owned(self) -> GreenElement { + match self { + NodeOrToken::Node(it) => NodeOrToken::Node(it.to_owned()), + NodeOrToken::Token(it) => NodeOrToken::Token(it.to_owned()), + } + } +} + +impl GreenElement { + /// Returns kind of this element. + #[inline] + pub fn kind(&self) -> SyntaxKind { + self.as_deref().kind() + } + + /// Returns the length of the text covered by this element. + #[inline] + pub fn text_len(&self) -> TextSize { + self.as_deref().text_len() + } +} + +impl GreenElementRef<'_> { + /// Returns kind of this element. + #[inline] + pub fn kind(&self) -> SyntaxKind { + match self { + NodeOrToken::Node(it) => it.kind(), + NodeOrToken::Token(it) => it.kind(), + } + } + + /// Returns the length of the text covered by this element. + #[inline] + pub fn text_len(self) -> TextSize { + match self { + NodeOrToken::Node(it) => it.text_len(), + NodeOrToken::Token(it) => it.text_len(), + } + } +} diff --git a/third_party/crates/rowan-0.16.1/src/green/node.rs b/third_party/crates/rowan-0.16.1/src/green/node.rs new file mode 100644 index 0000000..69b1cf7 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/green/node.rs @@ -0,0 +1,359 @@ +use std::{ + borrow::{Borrow, Cow}, + fmt, + iter::{self, FusedIterator}, + mem::{self, ManuallyDrop}, + ops, ptr, slice, +}; + +use countme::Count; + +use crate::{ + arc::{Arc, HeaderSlice, ThinArc}, + green::{GreenElement, GreenElementRef, SyntaxKind}, + utility_types::static_assert, + GreenToken, NodeOrToken, TextRange, TextSize, +}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(super) struct GreenNodeHead { + kind: SyntaxKind, + text_len: TextSize, + _c: Count, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) enum GreenChild { + Node { rel_offset: TextSize, node: GreenNode }, + Token { rel_offset: TextSize, token: GreenToken }, +} +#[cfg(target_pointer_width = "64")] +static_assert!(mem::size_of::() == mem::size_of::() * 2); + +type Repr = HeaderSlice; +type ReprThin = HeaderSlice; +#[repr(transparent)] +pub struct GreenNodeData { + data: ReprThin, +} + +impl PartialEq for GreenNodeData { + fn eq(&self, other: &Self) -> bool { + self.header() == other.header() && self.slice() == other.slice() + } +} + +/// Internal node in the immutable tree. +/// It has other nodes and tokens as children. +#[derive(Clone, PartialEq, Eq, Hash)] +#[repr(transparent)] +pub struct GreenNode { + ptr: ThinArc, +} + +impl ToOwned for GreenNodeData { + type Owned = GreenNode; + + #[inline] + fn to_owned(&self) -> GreenNode { + let green = unsafe { GreenNode::from_raw(ptr::NonNull::from(self)) }; + let green = ManuallyDrop::new(green); + GreenNode::clone(&green) + } +} + +impl Borrow for GreenNode { + #[inline] + fn borrow(&self) -> &GreenNodeData { + &*self + } +} + +impl From> for GreenNode { + #[inline] + fn from(cow: Cow<'_, GreenNodeData>) -> Self { + cow.into_owned() + } +} + +impl fmt::Debug for GreenNodeData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("GreenNode") + .field("kind", &self.kind()) + .field("text_len", &self.text_len()) + .field("n_children", &self.children().len()) + .finish() + } +} + +impl fmt::Debug for GreenNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data: &GreenNodeData = &*self; + fmt::Debug::fmt(data, f) + } +} + +impl fmt::Display for GreenNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data: &GreenNodeData = &*self; + fmt::Display::fmt(data, f) + } +} + +impl fmt::Display for GreenNodeData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for child in self.children() { + write!(f, "{}", child)?; + } + Ok(()) + } +} + +impl GreenNodeData { + #[inline] + fn header(&self) -> &GreenNodeHead { + &self.data.header + } + + #[inline] + fn slice(&self) -> &[GreenChild] { + self.data.slice() + } + + /// Kind of this node. + #[inline] + pub fn kind(&self) -> SyntaxKind { + self.header().kind + } + + /// Returns the length of the text covered by this node. + #[inline] + pub fn text_len(&self) -> TextSize { + self.header().text_len + } + + /// Children of this node. + #[inline] + pub fn children(&self) -> Children<'_> { + Children { raw: self.slice().iter() } + } + + pub(crate) fn child_at_range( + &self, + rel_range: TextRange, + ) -> Option<(usize, TextSize, GreenElementRef<'_>)> { + let idx = self + .slice() + .binary_search_by(|it| { + let child_range = it.rel_range(); + TextRange::ordering(child_range, rel_range) + }) + // XXX: this handles empty ranges + .unwrap_or_else(|it| it.saturating_sub(1)); + let child = &self.slice().get(idx).filter(|it| it.rel_range().contains_range(rel_range))?; + Some((idx, child.rel_offset(), child.as_ref())) + } + + #[must_use] + pub fn replace_child(&self, index: usize, new_child: GreenElement) -> GreenNode { + let mut replacement = Some(new_child); + let children = self.children().enumerate().map(|(i, child)| { + if i == index { + replacement.take().unwrap() + } else { + child.to_owned() + } + }); + GreenNode::new(self.kind(), children) + } + #[must_use] + pub fn insert_child(&self, index: usize, new_child: GreenElement) -> GreenNode { + // https://github.com/rust-lang/rust/issues/34433 + self.splice_children(index..index, iter::once(new_child)) + } + #[must_use] + pub fn remove_child(&self, index: usize) -> GreenNode { + self.splice_children(index..=index, iter::empty()) + } + #[must_use] + pub fn splice_children(&self, range: R, replace_with: I) -> GreenNode + where + R: ops::RangeBounds, + I: IntoIterator, + { + let mut children: Vec<_> = self.children().map(|it| it.to_owned()).collect(); + children.splice(range, replace_with); + GreenNode::new(self.kind(), children) + } +} + +impl ops::Deref for GreenNode { + type Target = GreenNodeData; + + #[inline] + fn deref(&self) -> &GreenNodeData { + let repr: &Repr = &self.ptr; + unsafe { + let repr: &ReprThin = &*(repr as *const Repr as *const ReprThin); + mem::transmute::<&ReprThin, &GreenNodeData>(repr) + } + } +} + +impl GreenNode { + /// Creates new Node. + #[inline] + pub fn new(kind: SyntaxKind, children: I) -> GreenNode + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + { + let mut text_len: TextSize = 0.into(); + let children = children.into_iter().map(|el| { + let rel_offset = text_len; + text_len += el.text_len(); + match el { + NodeOrToken::Node(node) => GreenChild::Node { rel_offset, node }, + NodeOrToken::Token(token) => GreenChild::Token { rel_offset, token }, + } + }); + + let data = ThinArc::from_header_and_iter( + GreenNodeHead { kind, text_len: 0.into(), _c: Count::new() }, + children, + ); + + // XXX: fixup `text_len` after construction, because we can't iterate + // `children` twice. + let data = { + let mut data = Arc::from_thin(data); + Arc::get_mut(&mut data).unwrap().header.text_len = text_len; + Arc::into_thin(data) + }; + + GreenNode { ptr: data } + } + + #[inline] + pub(crate) fn into_raw(this: GreenNode) -> ptr::NonNull { + let green = ManuallyDrop::new(this); + let green: &GreenNodeData = &*green; + ptr::NonNull::from(&*green) + } + + #[inline] + pub(crate) unsafe fn from_raw(ptr: ptr::NonNull) -> GreenNode { + let arc = Arc::from_raw(&ptr.as_ref().data as *const ReprThin); + let arc = mem::transmute::, ThinArc>(arc); + GreenNode { ptr: arc } + } +} + +impl GreenChild { + #[inline] + pub(crate) fn as_ref(&self) -> GreenElementRef { + match self { + GreenChild::Node { node, .. } => NodeOrToken::Node(node), + GreenChild::Token { token, .. } => NodeOrToken::Token(token), + } + } + #[inline] + pub(crate) fn rel_offset(&self) -> TextSize { + match self { + GreenChild::Node { rel_offset, .. } | GreenChild::Token { rel_offset, .. } => { + *rel_offset + } + } + } + #[inline] + fn rel_range(&self) -> TextRange { + let len = self.as_ref().text_len(); + TextRange::at(self.rel_offset(), len) + } +} + +#[derive(Debug, Clone)] +pub struct Children<'a> { + pub(crate) raw: slice::Iter<'a, GreenChild>, +} + +// NB: forward everything stable that iter::Slice specializes as of Rust 1.39.0 +impl ExactSizeIterator for Children<'_> { + #[inline(always)] + fn len(&self) -> usize { + self.raw.len() + } +} + +impl<'a> Iterator for Children<'a> { + type Item = GreenElementRef<'a>; + + #[inline] + fn next(&mut self) -> Option> { + self.raw.next().map(GreenChild::as_ref) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.raw.size_hint() + } + + #[inline] + fn count(self) -> usize + where + Self: Sized, + { + self.raw.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.raw.nth(n).map(GreenChild::as_ref) + } + + #[inline] + fn last(mut self) -> Option + where + Self: Sized, + { + self.next_back() + } + + #[inline] + fn fold(mut self, init: Acc, mut f: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x); + } + accum + } +} + +impl<'a> DoubleEndedIterator for Children<'a> { + #[inline] + fn next_back(&mut self) -> Option { + self.raw.next_back().map(GreenChild::as_ref) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.raw.nth_back(n).map(GreenChild::as_ref) + } + + #[inline] + fn rfold(mut self, init: Acc, mut f: Fold) -> Acc + where + Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x); + } + accum + } +} + +impl FusedIterator for Children<'_> {} diff --git a/third_party/crates/rowan-0.16.1/src/green/node_cache.rs b/third_party/crates/rowan-0.16.1/src/green/node_cache.rs new file mode 100644 index 0000000..c73f3e6 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/green/node_cache.rs @@ -0,0 +1,157 @@ +use hashbrown::hash_map::RawEntryMut; +use rustc_hash::FxHasher; +use std::hash::{BuildHasherDefault, Hash, Hasher}; + +use crate::{ + green::GreenElementRef, GreenNode, GreenNodeData, GreenToken, GreenTokenData, NodeOrToken, + SyntaxKind, +}; + +use super::element::GreenElement; + +type HashMap = hashbrown::HashMap>; + +#[derive(Debug)] +struct NoHash(T); + +/// Interner for GreenTokens and GreenNodes +// XXX: the impl is a bit tricky. As usual when writing interners, we want to +// store all values in one HashSet. +// +// However, hashing trees is fun: hash of the tree is recursively defined. We +// maintain an invariant -- if the tree is interned, then all of its children +// are interned as well. +// +// That means that computing the hash naively is wasteful -- we just *know* +// hashes of children, and we can re-use those. +// +// So here we use *raw* API of hashbrown and provide the hashes manually, +// instead of going via a `Hash` impl. Our manual `Hash` and the +// `#[derive(Hash)]` are actually different! At some point we had a fun bug, +// where we accidentally mixed the two hashes, which made the cache much less +// efficient. +// +// To fix that, we additionally wrap the data in `NoHash` wrapper, to make sure +// we don't accidentally use the wrong hash! +#[derive(Default, Debug)] +pub struct NodeCache { + nodes: HashMap, ()>, + tokens: HashMap, ()>, +} + +fn token_hash(token: &GreenTokenData) -> u64 { + let mut h = FxHasher::default(); + token.kind().hash(&mut h); + token.text().hash(&mut h); + h.finish() +} + +fn node_hash(node: &GreenNodeData) -> u64 { + let mut h = FxHasher::default(); + node.kind().hash(&mut h); + for child in node.children() { + match child { + NodeOrToken::Node(it) => node_hash(it), + NodeOrToken::Token(it) => token_hash(it), + } + .hash(&mut h) + } + h.finish() +} + +fn element_id(elem: GreenElementRef<'_>) -> *const () { + match elem { + NodeOrToken::Node(it) => it as *const GreenNodeData as *const (), + NodeOrToken::Token(it) => it as *const GreenTokenData as *const (), + } +} + +impl NodeCache { + pub(crate) fn node( + &mut self, + kind: SyntaxKind, + children: &mut Vec<(u64, GreenElement)>, + first_child: usize, + ) -> (u64, GreenNode) { + let build_node = move |children: &mut Vec<(u64, GreenElement)>| { + GreenNode::new(kind, children.drain(first_child..).map(|(_, it)| it)) + }; + + let children_ref = &children[first_child..]; + if children_ref.len() > 3 { + let node = build_node(children); + return (0, node); + } + + let hash = { + let mut h = FxHasher::default(); + kind.hash(&mut h); + for &(hash, _) in children_ref { + if hash == 0 { + let node = build_node(children); + return (0, node); + } + hash.hash(&mut h); + } + h.finish() + }; + + // Green nodes are fully immutable, so it's ok to deduplicate them. + // This is the same optimization that Roslyn does + // https://github.com/KirillOsenkov/Bliki/wiki/Roslyn-Immutable-Trees + // + // For example, all `#[inline]` in this file share the same green node! + // For `libsyntax/parse/parser.rs`, measurements show that deduping saves + // 17% of the memory for green nodes! + let entry = self.nodes.raw_entry_mut().from_hash(hash, |node| { + node.0.kind() == kind && node.0.children().len() == children_ref.len() && { + let lhs = node.0.children(); + let rhs = children_ref.iter().map(|(_, it)| it.as_deref()); + + let lhs = lhs.map(element_id); + let rhs = rhs.map(element_id); + + lhs.eq(rhs) + } + }); + + let node = match entry { + RawEntryMut::Occupied(entry) => { + drop(children.drain(first_child..)); + entry.key().0.clone() + } + RawEntryMut::Vacant(entry) => { + let node = build_node(children); + entry.insert_with_hasher(hash, NoHash(node.clone()), (), |n| node_hash(&n.0)); + node + } + }; + + (hash, node) + } + + pub(crate) fn token(&mut self, kind: SyntaxKind, text: &str) -> (u64, GreenToken) { + let hash = { + let mut h = FxHasher::default(); + kind.hash(&mut h); + text.hash(&mut h); + h.finish() + }; + + let entry = self + .tokens + .raw_entry_mut() + .from_hash(hash, |token| token.0.kind() == kind && token.0.text() == text); + + let token = match entry { + RawEntryMut::Occupied(entry) => entry.key().0.clone(), + RawEntryMut::Vacant(entry) => { + let token = GreenToken::new(kind, text); + entry.insert_with_hasher(hash, NoHash(token.clone()), (), |t| token_hash(&t.0)); + token + } + }; + + (hash, token) + } +} diff --git a/third_party/crates/rowan-0.16.1/src/green/token.rs b/third_party/crates/rowan-0.16.1/src/green/token.rs new file mode 100644 index 0000000..81e298c --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/green/token.rs @@ -0,0 +1,143 @@ +use std::{ + borrow::Borrow, + fmt, + mem::{self, ManuallyDrop}, + ops, ptr, +}; + +use countme::Count; + +use crate::{ + arc::{Arc, HeaderSlice, ThinArc}, + green::SyntaxKind, + TextSize, +}; + +#[derive(PartialEq, Eq, Hash)] +struct GreenTokenHead { + kind: SyntaxKind, + _c: Count, +} + +type Repr = HeaderSlice; +type ReprThin = HeaderSlice; +#[repr(transparent)] +pub struct GreenTokenData { + data: ReprThin, +} + +impl PartialEq for GreenTokenData { + fn eq(&self, other: &Self) -> bool { + self.kind() == other.kind() && self.text() == other.text() + } +} + +/// Leaf node in the immutable tree. +#[derive(PartialEq, Eq, Hash, Clone)] +#[repr(transparent)] +pub struct GreenToken { + ptr: ThinArc, +} + +impl ToOwned for GreenTokenData { + type Owned = GreenToken; + + #[inline] + fn to_owned(&self) -> GreenToken { + let green = unsafe { GreenToken::from_raw(ptr::NonNull::from(self)) }; + let green = ManuallyDrop::new(green); + GreenToken::clone(&green) + } +} + +impl Borrow for GreenToken { + #[inline] + fn borrow(&self) -> &GreenTokenData { + &*self + } +} + +impl fmt::Debug for GreenTokenData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("GreenToken") + .field("kind", &self.kind()) + .field("text", &self.text()) + .finish() + } +} + +impl fmt::Debug for GreenToken { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data: &GreenTokenData = &*self; + fmt::Debug::fmt(data, f) + } +} + +impl fmt::Display for GreenToken { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data: &GreenTokenData = &*self; + fmt::Display::fmt(data, f) + } +} + +impl fmt::Display for GreenTokenData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.text()) + } +} + +impl GreenTokenData { + /// Kind of this Token. + #[inline] + pub fn kind(&self) -> SyntaxKind { + self.data.header.kind + } + + /// Text of this Token. + #[inline] + pub fn text(&self) -> &str { + unsafe { std::str::from_utf8_unchecked(self.data.slice()) } + } + + /// Returns the length of the text covered by this token. + #[inline] + pub fn text_len(&self) -> TextSize { + TextSize::of(self.text()) + } +} + +impl GreenToken { + /// Creates new Token. + #[inline] + pub fn new(kind: SyntaxKind, text: &str) -> GreenToken { + let head = GreenTokenHead { kind, _c: Count::new() }; + let ptr = ThinArc::from_header_and_iter(head, text.bytes()); + GreenToken { ptr } + } + #[inline] + pub(crate) fn into_raw(this: GreenToken) -> ptr::NonNull { + let green = ManuallyDrop::new(this); + let green: &GreenTokenData = &*green; + ptr::NonNull::from(&*green) + } + + #[inline] + pub(crate) unsafe fn from_raw(ptr: ptr::NonNull) -> GreenToken { + let arc = Arc::from_raw(&ptr.as_ref().data as *const ReprThin); + let arc = mem::transmute::, ThinArc>(arc); + GreenToken { ptr: arc } + } +} + +impl ops::Deref for GreenToken { + type Target = GreenTokenData; + + #[inline] + fn deref(&self) -> &GreenTokenData { + unsafe { + let repr: &Repr = &self.ptr; + let repr: &ReprThin = &*(repr as *const Repr as *const ReprThin); + mem::transmute::<&ReprThin, &GreenTokenData>(repr) + } + } +} diff --git a/third_party/crates/rowan-0.16.1/src/lib.rs b/third_party/crates/rowan-0.16.1/src/lib.rs new file mode 100644 index 0000000..bb8f30d --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/lib.rs @@ -0,0 +1,41 @@ +//! A generic library for lossless syntax trees. +//! See `examples/s_expressions.rs` for a tutorial. +#![forbid( + // missing_debug_implementations, + unconditional_recursion, + future_incompatible, + // missing_docs, +)] +#![deny(unsafe_code)] + +#[allow(unsafe_code)] +mod green; +#[allow(unsafe_code)] +pub mod cursor; + +pub mod api; +mod syntax_text; +mod utility_types; + +mod cow_mut; +#[allow(unsafe_code)] +mod sll; +#[allow(unsafe_code)] +mod arc; +#[cfg(feature = "serde1")] +mod serde_impls; +pub mod ast; + +pub use text_size::{TextLen, TextRange, TextSize}; + +pub use crate::{ + api::{ + Language, SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, SyntaxToken, + }, + green::{ + Checkpoint, Children, GreenNode, GreenNodeBuilder, GreenNodeData, GreenToken, + GreenTokenData, NodeCache, SyntaxKind, + }, + syntax_text::SyntaxText, + utility_types::{Direction, NodeOrToken, TokenAtOffset, WalkEvent}, +}; diff --git a/third_party/crates/rowan-0.16.1/src/serde_impls.rs b/third_party/crates/rowan-0.16.1/src/serde_impls.rs new file mode 100644 index 0000000..aea5d88 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/serde_impls.rs @@ -0,0 +1,66 @@ +use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; +use std::fmt; + +use crate::{ + api::{Language, SyntaxNode, SyntaxToken}, + NodeOrToken, +}; + +struct SerDisplay(T); +impl Serialize for SerDisplay { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_str(&self.0) + } +} + +struct DisplayDebug(T); +impl fmt::Display for DisplayDebug { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl Serialize for SyntaxNode { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_map(Some(3))?; + state.serialize_entry("kind", &SerDisplay(DisplayDebug(self.kind())))?; + state.serialize_entry("text_range", &self.text_range())?; + state.serialize_entry("children", &Children(self))?; + state.end() + } +} + +impl Serialize for SyntaxToken { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_map(Some(3))?; + state.serialize_entry("kind", &SerDisplay(DisplayDebug(self.kind())))?; + state.serialize_entry("text_range", &self.text_range())?; + state.serialize_entry("text", &self.text())?; + state.end() + } +} + +struct Children(T); + +impl Serialize for Children<&'_ SyntaxNode> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_seq(None)?; + self.0.children_with_tokens().try_for_each(|element| match element { + NodeOrToken::Node(it) => state.serialize_element(&it), + NodeOrToken::Token(it) => state.serialize_element(&it), + })?; + state.end() + } +} diff --git a/third_party/crates/rowan-0.16.1/src/sll.rs b/third_party/crates/rowan-0.16.1/src/sll.rs new file mode 100644 index 0000000..4a29839 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/sll.rs @@ -0,0 +1,128 @@ +//! Sorted Linked List + +use std::{cell::Cell, cmp::Ordering, ptr}; + +use crate::utility_types::Delta; +pub(crate) unsafe trait Elem { + fn prev(&self) -> &Cell<*const Self>; + fn next(&self) -> &Cell<*const Self>; + fn key(&self) -> &Cell; +} + +pub(crate) enum AddToSllResult<'a, E: Elem> { + NoHead, + EmptyHead(&'a Cell<*const E>), + SmallerThanHead(&'a Cell<*const E>), + SmallerThanNotHead(*const E), + AlreadyInSll(*const E), +} + +impl<'a, E: Elem> AddToSllResult<'a, E> { + pub(crate) fn add_to_sll(&self, elem_ptr: *const E) { + unsafe { + (*elem_ptr).prev().set(elem_ptr); + (*elem_ptr).next().set(elem_ptr); + + match self { + // Case 1: empty head, replace it. + AddToSllResult::EmptyHead(head) => head.set(elem_ptr), + + // Case 2: we are smaller than the head, replace it. + AddToSllResult::SmallerThanHead(head) => { + let old_head = head.get(); + let prev = (*old_head).prev().replace(elem_ptr); + (*prev).next().set(elem_ptr); + (*elem_ptr).next().set(old_head); + (*elem_ptr).prev().set(prev); + head.set(elem_ptr); + } + + // Case 3: insert in place found by looping + AddToSllResult::SmallerThanNotHead(curr) => { + let next = (**curr).next().replace(elem_ptr); + (*next).prev().set(elem_ptr); + (*elem_ptr).prev().set(*curr); + (*elem_ptr).next().set(next); + } + AddToSllResult::NoHead | AddToSllResult::AlreadyInSll(_) => (), + } + } + } +} + +#[cold] +pub(crate) fn init<'a, E: Elem>( + head: Option<&'a Cell<*const E>>, + elem: &E, +) -> AddToSllResult<'a, E> { + if let Some(head) = head { + link(head, elem) + } else { + AddToSllResult::NoHead + } +} + +#[cold] +pub(crate) fn unlink(head: &Cell<*const E>, elem: &E) { + debug_assert!(!head.get().is_null(), "invalid linked list head"); + + let elem_ptr: *const E = elem; + + let prev = elem.prev().replace(elem_ptr); + let next = elem.next().replace(elem_ptr); + unsafe { + debug_assert_eq!((*prev).next().get(), elem_ptr, "invalid linked list links"); + debug_assert_eq!((*next).prev().get(), elem_ptr, "invalid linked list links"); + (*prev).next().set(next); + (*next).prev().set(prev); + } + + if head.get() == elem_ptr { + head.set(if next == elem_ptr { ptr::null() } else { next }) + } +} + +#[cold] +pub(crate) fn link<'a, E: Elem>(head: &'a Cell<*const E>, elem: &E) -> AddToSllResult<'a, E> { + let old_head = head.get(); + // Case 1: empty head, replace it. + if old_head.is_null() { + return AddToSllResult::EmptyHead(head); + } + unsafe { + // Case 2: we are smaller than the head, replace it. + if elem.key() < (*old_head).key() { + return AddToSllResult::SmallerThanHead(head); + } + + // Case 3: loop *backward* until we find insertion place. Because of + // Case 2, we can't loop beyond the head. + let mut curr = (*old_head).prev().get(); + loop { + match (*curr).key().cmp(elem.key()) { + Ordering::Less => return AddToSllResult::SmallerThanNotHead(curr), + Ordering::Equal => return AddToSllResult::AlreadyInSll(curr), + Ordering::Greater => curr = (*curr).prev().get(), + } + } + } +} + +pub(crate) fn adjust(elem: &E, from: u32, by: Delta) { + let elem_ptr: *const E = elem; + + unsafe { + let mut curr = elem_ptr; + loop { + let mut key = (*curr).key().get(); + if key >= from { + key += by; + (*curr).key().set(key); + } + curr = (*curr).next().get(); + if curr == elem_ptr { + break; + } + } + } +} diff --git a/third_party/crates/rowan-0.16.1/src/syntax_text.rs b/third_party/crates/rowan-0.16.1/src/syntax_text.rs new file mode 100644 index 0000000..3ab3f6c --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/syntax_text.rs @@ -0,0 +1,311 @@ +use std::fmt; + +use crate::{ + cursor::{SyntaxNode, SyntaxToken}, + TextRange, TextSize, +}; + +#[derive(Clone)] +pub struct SyntaxText { + node: SyntaxNode, + range: TextRange, +} + +impl SyntaxText { + pub(crate) fn new(node: SyntaxNode) -> SyntaxText { + let range = node.text_range(); + SyntaxText { node, range } + } + + pub fn len(&self) -> TextSize { + self.range.len() + } + + pub fn is_empty(&self) -> bool { + self.range.is_empty() + } + + pub fn contains_char(&self, c: char) -> bool { + self.try_for_each_chunk(|chunk| if chunk.contains(c) { Err(()) } else { Ok(()) }).is_err() + } + + pub fn find_char(&self, c: char) -> Option { + let mut acc: TextSize = 0.into(); + let res = self.try_for_each_chunk(|chunk| { + if let Some(pos) = chunk.find(c) { + let pos: TextSize = (pos as u32).into(); + return Err(acc + pos); + } + acc += TextSize::of(chunk); + Ok(()) + }); + found(res) + } + + pub fn char_at(&self, offset: TextSize) -> Option { + let offset = offset.into(); + let mut start: TextSize = 0.into(); + let res = self.try_for_each_chunk(|chunk| { + let end = start + TextSize::of(chunk); + if start <= offset && offset < end { + let off: usize = u32::from(offset - start) as usize; + return Err(chunk[off..].chars().next().unwrap()); + } + start = end; + Ok(()) + }); + found(res) + } + + pub fn slice(&self, range: R) -> SyntaxText { + let start = range.start().unwrap_or_default(); + let end = range.end().unwrap_or(self.len()); + assert!(start <= end); + let len = end - start; + let start = self.range.start() + start; + let end = start + len; + assert!( + start <= end, + "invalid slice, range: {:?}, slice: {:?}", + self.range, + (range.start(), range.end()), + ); + let range = TextRange::new(start, end); + assert!( + self.range.contains_range(range), + "invalid slice, range: {:?}, slice: {:?}", + self.range, + range, + ); + SyntaxText { node: self.node.clone(), range } + } + + pub fn try_fold_chunks(&self, init: T, mut f: F) -> Result + where + F: FnMut(T, &str) -> Result, + { + self.tokens_with_ranges() + .try_fold(init, move |acc, (token, range)| f(acc, &token.text()[range])) + } + + pub fn try_for_each_chunk Result<(), E>, E>( + &self, + mut f: F, + ) -> Result<(), E> { + self.try_fold_chunks((), move |(), chunk| f(chunk)) + } + + pub fn for_each_chunk(&self, mut f: F) { + enum Void {} + match self.try_for_each_chunk(|chunk| Ok::<(), Void>(f(chunk))) { + Ok(()) => (), + Err(void) => match void {}, + } + } + + fn tokens_with_ranges(&self) -> impl Iterator { + let text_range = self.range; + self.node.descendants_with_tokens().filter_map(|element| element.into_token()).filter_map( + move |token| { + let token_range = token.text_range(); + let range = text_range.intersect(token_range)?; + Some((token, range - token_range.start())) + }, + ) + } +} + +fn found(res: Result<(), T>) -> Option { + match res { + Ok(()) => None, + Err(it) => Some(it), + } +} + +impl fmt::Debug for SyntaxText { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.to_string(), f) + } +} + +impl fmt::Display for SyntaxText { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.try_for_each_chunk(|chunk| fmt::Display::fmt(chunk, f)) + } +} + +impl From for String { + fn from(text: SyntaxText) -> String { + text.to_string() + } +} + +impl PartialEq for SyntaxText { + fn eq(&self, mut rhs: &str) -> bool { + self.try_for_each_chunk(|chunk| { + if !rhs.starts_with(chunk) { + return Err(()); + } + rhs = &rhs[chunk.len()..]; + Ok(()) + }) + .is_ok() + && rhs.is_empty() + } +} + +impl PartialEq for str { + fn eq(&self, rhs: &SyntaxText) -> bool { + rhs == self + } +} + +impl PartialEq<&'_ str> for SyntaxText { + fn eq(&self, rhs: &&str) -> bool { + self == *rhs + } +} + +impl PartialEq for &'_ str { + fn eq(&self, rhs: &SyntaxText) -> bool { + rhs == self + } +} + +impl PartialEq for SyntaxText { + fn eq(&self, other: &SyntaxText) -> bool { + if self.range.len() != other.range.len() { + return false; + } + let mut lhs = self.tokens_with_ranges(); + let mut rhs = other.tokens_with_ranges(); + zip_texts(&mut lhs, &mut rhs).is_none() + && lhs.all(|it| it.1.is_empty()) + && rhs.all(|it| it.1.is_empty()) + } +} + +fn zip_texts>(xs: &mut I, ys: &mut I) -> Option<()> { + let mut x = xs.next()?; + let mut y = ys.next()?; + loop { + while x.1.is_empty() { + x = xs.next()?; + } + while y.1.is_empty() { + y = ys.next()?; + } + let x_text = &x.0.text()[x.1]; + let y_text = &y.0.text()[y.1]; + if !(x_text.starts_with(y_text) || y_text.starts_with(x_text)) { + return Some(()); + } + let advance = std::cmp::min(x.1.len(), y.1.len()); + x.1 = TextRange::new(x.1.start() + advance, x.1.end()); + y.1 = TextRange::new(y.1.start() + advance, y.1.end()); + } +} + +impl Eq for SyntaxText {} + +mod private { + use std::ops; + + use crate::{TextRange, TextSize}; + + pub trait SyntaxTextRange { + fn start(&self) -> Option; + fn end(&self) -> Option; + } + + impl SyntaxTextRange for TextRange { + fn start(&self) -> Option { + Some(TextRange::start(*self)) + } + fn end(&self) -> Option { + Some(TextRange::end(*self)) + } + } + + impl SyntaxTextRange for ops::Range { + fn start(&self) -> Option { + Some(self.start) + } + fn end(&self) -> Option { + Some(self.end) + } + } + + impl SyntaxTextRange for ops::RangeFrom { + fn start(&self) -> Option { + Some(self.start) + } + fn end(&self) -> Option { + None + } + } + + impl SyntaxTextRange for ops::RangeTo { + fn start(&self) -> Option { + None + } + fn end(&self) -> Option { + Some(self.end) + } + } + + impl SyntaxTextRange for ops::RangeFull { + fn start(&self) -> Option { + None + } + fn end(&self) -> Option { + None + } + } +} + +#[cfg(test)] +mod tests { + use crate::{green::SyntaxKind, GreenNodeBuilder}; + + use super::*; + + fn build_tree(chunks: &[&str]) -> SyntaxNode { + let mut builder = GreenNodeBuilder::new(); + builder.start_node(SyntaxKind(62)); + for &chunk in chunks.iter() { + builder.token(SyntaxKind(92), chunk.into()) + } + builder.finish_node(); + SyntaxNode::new_root(builder.finish()) + } + + #[test] + fn test_text_equality() { + fn do_check(t1: &[&str], t2: &[&str]) { + let t1 = build_tree(t1).text(); + let t2 = build_tree(t2).text(); + let expected = t1.to_string() == t2.to_string(); + let actual = t1 == t2; + assert_eq!(expected, actual, "`{}` (SyntaxText) `{}` (SyntaxText)", t1, t2); + let actual = t1 == &*t2.to_string(); + assert_eq!(expected, actual, "`{}` (SyntaxText) `{}` (&str)", t1, t2); + } + fn check(t1: &[&str], t2: &[&str]) { + do_check(t1, t2); + do_check(t2, t1) + } + + check(&[""], &[""]); + check(&["a"], &[""]); + check(&["a"], &["a"]); + check(&["abc"], &["def"]); + check(&["hello", "world"], &["hello", "world"]); + check(&["hellowo", "rld"], &["hell", "oworld"]); + check(&["hel", "lowo", "rld"], &["helloworld"]); + check(&["{", "abc", "}"], &["{", "123", "}"]); + check(&["{", "abc", "}", "{"], &["{", "123", "}"]); + check(&["{", "abc", "}"], &["{", "123", "}", "{"]); + check(&["{", "abc", "}ab"], &["{", "abc", "}", "ab"]); + } +} diff --git a/third_party/crates/rowan-0.16.1/src/utility_types.rs b/third_party/crates/rowan-0.16.1/src/utility_types.rs new file mode 100644 index 0000000..817add7 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/src/utility_types.rs @@ -0,0 +1,180 @@ +use std::{ + fmt, + ops::{AddAssign, Deref}, +}; +use text_size::TextSize; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum NodeOrToken { + Node(N), + Token(T), +} + +impl NodeOrToken { + pub fn into_node(self) -> Option { + match self { + NodeOrToken::Node(node) => Some(node), + NodeOrToken::Token(_) => None, + } + } + + pub fn into_token(self) -> Option { + match self { + NodeOrToken::Node(_) => None, + NodeOrToken::Token(token) => Some(token), + } + } + + pub fn as_node(&self) -> Option<&N> { + match self { + NodeOrToken::Node(node) => Some(node), + NodeOrToken::Token(_) => None, + } + } + + pub fn as_token(&self) -> Option<&T> { + match self { + NodeOrToken::Node(_) => None, + NodeOrToken::Token(token) => Some(token), + } + } +} + +impl NodeOrToken { + pub(crate) fn as_deref(&self) -> NodeOrToken<&N::Target, &T::Target> { + match self { + NodeOrToken::Node(node) => NodeOrToken::Node(&*node), + NodeOrToken::Token(token) => NodeOrToken::Token(&*token), + } + } +} + +impl fmt::Display for NodeOrToken { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + NodeOrToken::Node(node) => fmt::Display::fmt(node, f), + NodeOrToken::Token(token) => fmt::Display::fmt(token, f), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Direction { + Next, + Prev, +} + +/// `WalkEvent` describes tree walking process. +#[derive(Debug, Copy, Clone)] +pub enum WalkEvent { + /// Fired before traversing the node. + Enter(T), + /// Fired after the node is traversed. + Leave(T), +} + +impl WalkEvent { + pub fn map U, U>(self, f: F) -> WalkEvent { + match self { + WalkEvent::Enter(it) => WalkEvent::Enter(f(it)), + WalkEvent::Leave(it) => WalkEvent::Leave(f(it)), + } + } +} + +/// There might be zero, one or two leaves at a given offset. +#[derive(Clone, Debug)] +pub enum TokenAtOffset { + /// No leaves at offset -- possible for the empty file. + None, + /// Only a single leaf at offset. + Single(T), + /// Offset is exactly between two leaves. + Between(T, T), +} + +impl TokenAtOffset { + pub fn map U, U>(self, f: F) -> TokenAtOffset { + match self { + TokenAtOffset::None => TokenAtOffset::None, + TokenAtOffset::Single(it) => TokenAtOffset::Single(f(it)), + TokenAtOffset::Between(l, r) => TokenAtOffset::Between(f(l), f(r)), + } + } + + /// Convert to option, preferring the right leaf in case of a tie. + pub fn right_biased(self) -> Option { + match self { + TokenAtOffset::None => None, + TokenAtOffset::Single(node) => Some(node), + TokenAtOffset::Between(_, right) => Some(right), + } + } + + /// Convert to option, preferring the left leaf in case of a tie. + pub fn left_biased(self) -> Option { + match self { + TokenAtOffset::None => None, + TokenAtOffset::Single(node) => Some(node), + TokenAtOffset::Between(left, _) => Some(left), + } + } +} + +impl Iterator for TokenAtOffset { + type Item = T; + + fn next(&mut self) -> Option { + match std::mem::replace(self, TokenAtOffset::None) { + TokenAtOffset::None => None, + TokenAtOffset::Single(node) => { + *self = TokenAtOffset::None; + Some(node) + } + TokenAtOffset::Between(left, right) => { + *self = TokenAtOffset::Single(right); + Some(left) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + match self { + TokenAtOffset::None => (0, Some(0)), + TokenAtOffset::Single(_) => (1, Some(1)), + TokenAtOffset::Between(_, _) => (2, Some(2)), + } + } +} + +impl ExactSizeIterator for TokenAtOffset {} + +macro_rules! _static_assert { + ($expr:expr) => { + const _: i32 = 0 / $expr as i32; + }; +} + +pub(crate) use _static_assert as static_assert; + +#[derive(Copy, Clone, Debug)] +pub(crate) enum Delta { + Add(T), + Sub(T), +} + +// This won't be coherent :-( +// impl AddAssign> for T +macro_rules! impls { + ($($ty:ident)*) => {$( + impl AddAssign> for $ty { + fn add_assign(&mut self, rhs: Delta<$ty>) { + match rhs { + Delta::Add(amt) => *self += amt, + Delta::Sub(amt) => *self -= amt, + } + } + } + )*}; +} +impls!(u32 TextSize); diff --git a/third_party/crates/rowan-0.16.1/tests/tidy.rs b/third_party/crates/rowan-0.16.1/tests/tidy.rs new file mode 100644 index 0000000..a716e35 --- /dev/null +++ b/third_party/crates/rowan-0.16.1/tests/tidy.rs @@ -0,0 +1,46 @@ +use std::{ + env, + path::{Path, PathBuf}, + process::{Command, Stdio}, +}; + +fn project_root() -> PathBuf { + PathBuf::from( + env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()), + ) +} + +fn run(cmd: &str, dir: impl AsRef) -> Result<(), ()> { + let mut args: Vec<_> = cmd.split_whitespace().collect(); + let bin = args.remove(0); + println!("> {}", cmd); + let output = Command::new(bin) + .args(args) + .current_dir(dir) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .output() + .map_err(drop)?; + if output.status.success() { + Ok(()) + } else { + let stdout = String::from_utf8(output.stdout).map_err(drop)?; + print!("{}", stdout); + Err(()) + } +} + +#[test] +fn check_code_formatting() { + let dir = project_root(); + if run("rustfmt +stable --version", &dir).is_err() { + panic!( + "failed to run rustfmt from toolchain 'stable'; \ + please run `rustup component add rustfmt --toolchain stable` to install it.", + ); + } + if run("cargo +stable fmt -- --check", &dir).is_err() { + panic!("code is not properly formatted; please format the code by running `cargo fmt`") + } +} diff --git a/third_party/crates/rustc-hash-1.1.0/.cargo-checksum.json b/third_party/crates/rustc-hash-1.1.0/.cargo-checksum.json new file mode 100644 index 0000000..3194e37 --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"7fe00878e217385a2b89256f7a2d6bb1bdc9eac39365df004eeb373441b632c5","CODE_OF_CONDUCT.md":"edca092fde496419a9f1ba640048aa0270b62dfea576cd3175f0b53e3c230470","Cargo.toml":"647814b27b6fc4fbef1df70d796b53b723e776b68467372044e4182763007379","Cargo.toml.orig":"da35209ae338cf5c7d5303042f9d4eb8dffa0d8dc92d7817e9820a2b6d3b1380","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"cac8197ac869d64a6efc26cab883a269392ae6db51f7453bca722f8f31d67c7c","src/lib.rs":"ddecafb5db609d0d8eebd19e4d98dc865e7e9282a4183421f9bd765c01a231c0"},"package":"08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"} \ No newline at end of file diff --git a/third_party/crates/rustc-hash-1.1.0/.cargo_vcs_info.json b/third_party/crates/rustc-hash-1.1.0/.cargo_vcs_info.json new file mode 100644 index 0000000..1e883e8 --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/.cargo_vcs_info.json @@ -0,0 +1,5 @@ +{ + "git": { + "sha1": "6fc9a706a9312ee801c7e77ca06c0782fa9eadef" + } +} diff --git a/third_party/crates/rustc-hash-1.1.0/BUILD.bazel b/third_party/crates/rustc-hash-1.1.0/BUILD.bazel new file mode 100644 index 0000000..5c5e7be --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/BUILD.bazel @@ -0,0 +1,114 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "rustc_hash", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_features = [ + "default", + "std", + ], + crate_root = "src/lib.rs", + edition = "2015", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=rustc-hash", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.1.0", +) diff --git a/third_party/crates/rustc-hash-1.1.0/CODE_OF_CONDUCT.md b/third_party/crates/rustc-hash-1.1.0/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..d70b2b5 --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/CODE_OF_CONDUCT.md @@ -0,0 +1,40 @@ +# The Rust Code of Conduct + +A version of this document [can be found online](https://www.rust-lang.org/conduct.html). + +## Conduct + +**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org) + +* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. +* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. +* Please be kind and courteous. There's no need to be mean or rude. +* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. +* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. +* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. +* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. +* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. + +## Moderation + + +These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team]. + +1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.) +2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed. +3. Moderators will first respond to such remarks with a warning. +4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off. +5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded. +6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology. +7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed. +8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others. + +In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely. + +And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust. + +The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust, #rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion. + +*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).* + +[mod_team]: https://www.rust-lang.org/team.html#Moderation-team diff --git a/third_party/crates/rustc-hash-1.1.0/Cargo.toml b/third_party/crates/rustc-hash-1.1.0/Cargo.toml new file mode 100644 index 0000000..47330b7 --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "rustc-hash" +version = "1.1.0" +authors = ["The Rust Project Developers"] +description = "speed, non-cryptographic hash used in rustc" +readme = "README.md" +keywords = ["hash", "fxhash", "rustc"] +license = "Apache-2.0/MIT" +repository = "https://github.com/rust-lang-nursery/rustc-hash" + +[features] +default = ["std"] +std = [] diff --git a/third_party/crates/rustc-hash-1.1.0/Cargo.toml.orig b/third_party/crates/rustc-hash-1.1.0/Cargo.toml.orig new file mode 100644 index 0000000..a28fdb9 --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/Cargo.toml.orig @@ -0,0 +1,13 @@ +[package] +name = "rustc-hash" +version = "1.1.0" +authors = ["The Rust Project Developers"] +description = "speed, non-cryptographic hash used in rustc" +license = "Apache-2.0/MIT" +readme = "README.md" +keywords = ["hash", "fxhash", "rustc"] +repository = "https://github.com/rust-lang-nursery/rustc-hash" + +[features] +std = [] +default = ["std"] diff --git a/third_party/crates/rustc-hash-1.1.0/LICENSE-APACHE b/third_party/crates/rustc-hash-1.1.0/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/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/third_party/crates/rustc-hash-1.1.0/LICENSE-MIT b/third_party/crates/rustc-hash-1.1.0/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/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/third_party/crates/rustc-hash-1.1.0/README.md b/third_party/crates/rustc-hash-1.1.0/README.md new file mode 100644 index 0000000..e33057a --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/README.md @@ -0,0 +1,38 @@ +# rustc-hash + +[![crates.io](https://img.shields.io/crates/v/rustc-hash.svg)](https://crates.io/crates/rustc-hash) +[![Documentation](https://docs.rs/rustc-hash/badge.svg)](https://docs.rs/rustc-hash) + +A speedy hash algorithm used within rustc. The hashmap in liballoc by +default uses SipHash which isn't quite as speedy as we want. In the +compiler we're not really worried about DOS attempts, so we use a fast +non-cryptographic hash. + +This is the same as the algorithm used by Firefox -- which is a +homespun one not based on any widely-known algorithm -- though +modified to produce 64-bit hash values instead of 32-bit hash +values. It consistently out-performs an FNV-based hash within rustc +itself -- the collision rate is similar or slightly worse than FNV, +but the speed of the hash function itself is much higher because it +works on up to 8 bytes at a time. + +## Usage + +```rust +use rustc_hash::FxHashMap; + +let mut map: FxHashMap = FxHashMap::default(); +map.insert(22, 44); +``` + +### `no_std` + +This crate can be used as a `no_std` crate by disabling the `std` +feature, which is on by default, as follows: + +```toml +rustc-hash = { version = "1.0", default-features = false } +``` + +In this configuration, `FxHasher` is the only export, and the +`FxHashMap`/`FxHashSet` type aliases are omitted. diff --git a/third_party/crates/rustc-hash-1.1.0/src/lib.rs b/third_party/crates/rustc-hash-1.1.0/src/lib.rs new file mode 100644 index 0000000..ee9ad31 --- /dev/null +++ b/third_party/crates/rustc-hash-1.1.0/src/lib.rs @@ -0,0 +1,148 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Fast, non-cryptographic hash used by rustc and Firefox. +//! +//! # Example +//! +//! ```rust +//! # #[cfg(feature = "std")] +//! # fn main() { +//! use rustc_hash::FxHashMap; +//! let mut map: FxHashMap = FxHashMap::default(); +//! map.insert(22, 44); +//! # } +//! # #[cfg(not(feature = "std"))] +//! # fn main() { } +//! ``` + +#![no_std] + +#[cfg(feature = "std")] +extern crate std; + +use core::convert::TryInto; +use core::default::Default; +#[cfg(feature = "std")] +use core::hash::BuildHasherDefault; +use core::hash::Hasher; +use core::mem::size_of; +use core::ops::BitXor; +#[cfg(feature = "std")] +use std::collections::{HashMap, HashSet}; + +/// Type alias for a hashmap using the `fx` hash algorithm. +#[cfg(feature = "std")] +pub type FxHashMap = HashMap>; + +/// Type alias for a hashmap using the `fx` hash algorithm. +#[cfg(feature = "std")] +pub type FxHashSet = HashSet>; + +/// A speedy hash algorithm for use within rustc. The hashmap in liballoc +/// by default uses SipHash which isn't quite as speedy as we want. In the +/// compiler we're not really worried about DOS attempts, so we use a fast +/// non-cryptographic hash. +/// +/// This is the same as the algorithm used by Firefox -- which is a homespun +/// one not based on any widely-known algorithm -- though modified to produce +/// 64-bit hash values instead of 32-bit hash values. It consistently +/// out-performs an FNV-based hash within rustc itself -- the collision rate is +/// similar or slightly worse than FNV, but the speed of the hash function +/// itself is much higher because it works on up to 8 bytes at a time. +pub struct FxHasher { + hash: usize, +} + +#[cfg(target_pointer_width = "32")] +const K: usize = 0x9e3779b9; +#[cfg(target_pointer_width = "64")] +const K: usize = 0x517cc1b727220a95; + +impl Default for FxHasher { + #[inline] + fn default() -> FxHasher { + FxHasher { hash: 0 } + } +} + +impl FxHasher { + #[inline] + fn add_to_hash(&mut self, i: usize) { + self.hash = self.hash.rotate_left(5).bitxor(i).wrapping_mul(K); + } +} + +impl Hasher for FxHasher { + #[inline] + fn write(&mut self, mut bytes: &[u8]) { + #[cfg(target_pointer_width = "32")] + let read_usize = |bytes: &[u8]| u32::from_ne_bytes(bytes[..4].try_into().unwrap()); + #[cfg(target_pointer_width = "64")] + let read_usize = |bytes: &[u8]| u64::from_ne_bytes(bytes[..8].try_into().unwrap()); + + let mut hash = FxHasher { hash: self.hash }; + assert!(size_of::() <= 8); + while bytes.len() >= size_of::() { + hash.add_to_hash(read_usize(bytes) as usize); + bytes = &bytes[size_of::()..]; + } + if (size_of::() > 4) && (bytes.len() >= 4) { + hash.add_to_hash(u32::from_ne_bytes(bytes[..4].try_into().unwrap()) as usize); + bytes = &bytes[4..]; + } + if (size_of::() > 2) && bytes.len() >= 2 { + hash.add_to_hash(u16::from_ne_bytes(bytes[..2].try_into().unwrap()) as usize); + bytes = &bytes[2..]; + } + if (size_of::() > 1) && bytes.len() >= 1 { + hash.add_to_hash(bytes[0] as usize); + } + self.hash = hash.hash; + } + + #[inline] + fn write_u8(&mut self, i: u8) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.add_to_hash(i as usize); + } + + #[cfg(target_pointer_width = "32")] + #[inline] + fn write_u64(&mut self, i: u64) { + self.add_to_hash(i as usize); + self.add_to_hash((i >> 32) as usize); + } + + #[cfg(target_pointer_width = "64")] + #[inline] + fn write_u64(&mut self, i: u64) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_usize(&mut self, i: usize) { + self.add_to_hash(i); + } + + #[inline] + fn finish(&self) -> u64 { + self.hash as u64 + } +} diff --git a/third_party/crates/text-size-1.1.1/.cargo-checksum.json b/third_party/crates/text-size-1.1.1/.cargo-checksum.json new file mode 100644 index 0000000..a55508e --- /dev/null +++ b/third_party/crates/text-size-1.1.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"7aee1130fbd28cb53c3076e5896129f8258c5e2e5ddb3b09d4105b52fe880599",".github/workflows/ci.yaml":"3a8ee5ed025def9f7d7a64f9c4309e0e4df8dba4989a528a0f1e9da48fae3001","CHANGELOG.md":"88259e5af5066d26c596d9957ab21c1b492c55203703b3b5b871f44320f47017","Cargo.toml":"7a97e8fe3dabc009da1aa1c773dff9e5bfe4215602390baebc6e1acaba91fa0d","Cargo.toml.orig":"13bf4dfee32010a146439d18ad7221bd274a161eb44438d65211270b90f53a5d","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"7f7ac8467b916ae7914e22dfebd86e75780153b2c0c96df6d5a4770c84e2b1a8","bors.toml":"b3496e907b819b61ee888711f6d913f9c6642132b4a81cd7cfcba9b92f273ad3","src/lib.rs":"2fcfb9d9b5ac54f3e06583561ce9e62aa5c824e29c15c6d013d12f42231504c1","src/range.rs":"d458a1f4d236d171cace505151536691dfa4bfb9974e3a3f3349719ac6fbfd6e","src/serde_impls.rs":"ecf184114eb2792a06ca65ba4bb2666f7152671728ff9b33c62900a29a557a8f","src/size.rs":"c6af100f2ef9aa8f0acec3826c2e70570baa37e6d40db4174f763cda43818ff3","src/traits.rs":"3a1a482195c97fd1cac835cb598d9c8b0b83e52159c242b1e7d19f95b4bd58cb","tests/auto_traits.rs":"ed1b81a43a403a5d45f00c15e032f49d24248d104aff4b1508ade73058868e6d","tests/constructors.rs":"59e428345ec34395d66e75632b1399946723377fa967da103221799500f12a0e","tests/indexing.rs":"bbe82f6666ec37e27270e950e52cd241a84b3a3ad97c98fc834665518030c126","tests/main.rs":"efdd3e2f184db61bc8dd9528f689cd61d657a5f1d884d67575e05b9d5f3a8539","tests/serde.rs":"a94202e76d98baf8a81ce7077422882db723534df6bb1091e1c64ab6fd7ccd07"},"package":"f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"} \ No newline at end of file diff --git a/third_party/crates/text-size-1.1.1/.cargo_vcs_info.json b/third_party/crates/text-size-1.1.1/.cargo_vcs_info.json new file mode 100644 index 0000000..c02c763 --- /dev/null +++ b/third_party/crates/text-size-1.1.1/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "5f22fbe12550a2c70caff9a8c5347d6722370469" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/third_party/crates/text-size-1.1.1/.github/workflows/ci.yaml b/third_party/crates/text-size-1.1.1/.github/workflows/ci.yaml new file mode 100644 index 0000000..50079ca --- /dev/null +++ b/third_party/crates/text-size-1.1.1/.github/workflows/ci.yaml @@ -0,0 +1,54 @@ +name: CI +on: + pull_request: + push: + branches: + - master + - staging + - trying + +env: + RUSTFLAGS: -D warnings + RUSTUP_MAX_RETRIES: 10 + CARGO_NET_RETRY: 10 + +jobs: + rust: + name: Rust + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + + - name: Test + run: cargo test --all-features + + rustdoc: + name: Docs + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + profile: minimal + override: true + + - name: Rustdoc + run: cargo rustdoc --all-features -- -D warnings diff --git a/third_party/crates/text-size-1.1.1/BUILD.bazel b/third_party/crates/text-size-1.1.1/BUILD.bazel new file mode 100644 index 0000000..aefcf67 --- /dev/null +++ b/third_party/crates/text-size-1.1.1/BUILD.bazel @@ -0,0 +1,110 @@ +############################################################################### +# @generated +# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To +# regenerate this file, run the following: +# +# bazel run @@//third_party:vendor_crates +############################################################################### + +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_library") + +package(default_visibility = ["//visibility:public"]) + +cargo_toml_env_vars( + name = "cargo_toml_env_vars", + src = "Cargo.toml", +) + +rust_library( + name = "text_size", + srcs = glob( + include = ["**/*.rs"], + allow_empty = False, + ), + compile_data = glob( + include = ["**"], + allow_empty = True, + exclude = [ + "**/* *", + ".tmp_git_root/**/*", + "BUILD", + "BUILD.bazel", + "WORKSPACE", + "WORKSPACE.bazel", + ], + ), + crate_root = "src/lib.rs", + edition = "2018", + rustc_env_files = [ + ":cargo_toml_env_vars", + ], + rustc_flags = [ + "--cap-lints=allow", + ], + tags = [ + "cargo-bazel", + "crate-name=text-size", + "manual", + "noclippy", + "norustfmt", + ], + target_compatible_with = select({ + "@rules_rust//rust/platform:aarch64-apple-darwin": [], + "@rules_rust//rust/platform:aarch64-apple-ios": [], + "@rules_rust//rust/platform:aarch64-apple-ios-macabi": [], + "@rules_rust//rust/platform:aarch64-apple-ios-sim": [], + "@rules_rust//rust/platform:aarch64-linux-android": [], + "@rules_rust//rust/platform:aarch64-pc-windows-msvc": [], + "@rules_rust//rust/platform:aarch64-unknown-fuchsia": [], + "@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:aarch64-unknown-none": [], + "@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [], + "@rules_rust//rust/platform:aarch64-unknown-uefi": [], + "@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:arm-unknown-linux-musleabi": [], + "@rules_rust//rust/platform:armv7-linux-androideabi": [], + "@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [], + "@rules_rust//rust/platform:i686-apple-darwin": [], + "@rules_rust//rust/platform:i686-linux-android": [], + "@rules_rust//rust/platform:i686-pc-windows-msvc": [], + "@rules_rust//rust/platform:i686-unknown-freebsd": [], + "@rules_rust//rust/platform:i686-unknown-linux-gnu": [], + "@rules_rust//rust/platform:loongarch64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:mips-unknown-linux-gnu": [], + "@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv32imac-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [], + "@rules_rust//rust/platform:riscv64gc-unknown-linux-gnu": [], + "@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [], + "@rules_rust//rust/platform:s390x-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:sparc64-unknown-netbsd": [], + "@rules_rust//rust/platform:sparc64-unknown-openbsd": [], + "@rules_rust//rust/platform:thumbv6m-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabi": [], + "@rules_rust//rust/platform:thumbv7em-none-eabihf": [], + "@rules_rust//rust/platform:thumbv7m-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabi": [], + "@rules_rust//rust/platform:thumbv8m.main-none-eabihf": [], + "@rules_rust//rust/platform:wasm32-unknown-emscripten": [], + "@rules_rust//rust/platform:wasm32-unknown-unknown": [], + "@rules_rust//rust/platform:wasm32-wasip1": [], + "@rules_rust//rust/platform:wasm32-wasip1-threads": [], + "@rules_rust//rust/platform:wasm32-wasip2": [], + "@rules_rust//rust/platform:x86_64-apple-darwin": [], + "@rules_rust//rust/platform:x86_64-apple-ios": [], + "@rules_rust//rust/platform:x86_64-apple-ios-macabi": [], + "@rules_rust//rust/platform:x86_64-linux-android": [], + "@rules_rust//rust/platform:x86_64-pc-windows-msvc": [], + "@rules_rust//rust/platform:x86_64-unknown-freebsd": [], + "@rules_rust//rust/platform:x86_64-unknown-fuchsia": [], + "@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [], + "@rules_rust//rust/platform:x86_64-unknown-none": [], + "@rules_rust//rust/platform:x86_64-unknown-uefi": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + version = "1.1.1", +) diff --git a/third_party/crates/text-size-1.1.1/CHANGELOG.md b/third_party/crates/text-size-1.1.1/CHANGELOG.md new file mode 100644 index 0000000..4f8c9af --- /dev/null +++ b/third_party/crates/text-size-1.1.1/CHANGELOG.md @@ -0,0 +1,26 @@ +# Changelog + +## 1.1.0 + +* add `TextRange::ordering` method + +## 1.0.0 :tada: + +* the carate is renamed to `text-size` from `text_unit` + +Transition table: +- `TextUnit::of_char(c)` ⟹ `TextSize::of(c)` +- `TextUnit::of_str(s)` ⟹ `TextSize::of(s)` +- `TextUnit::from_usize(size)` ⟹ `TextSize::try_from(size).unwrap_or_else(|| panic!(_))` +- `unit.to_usize()` ⟹ `usize::from(size)` +- `TextRange::from_to(from, to)` ⟹ `TextRange::new(from, to)` +- `TextRange::offset_len(offset, size)` ⟹ `TextRange::from_len(offset, size)` +- `range.start()` ⟹ `range.start()` +- `range.end()` ⟹ `range.end()` +- `range.len()` ⟹ `range.len()` +- `range.is_empty()` ⟹ `range.is_empty()` +- `a.is_subrange(b)` ⟹ `b.contains_range(a)` +- `a.intersection(b)` ⟹ `a.intersect(b)` +- `a.extend_to(b)` ⟹ `a.cover(b)` +- `range.contains(offset)` ⟹ `range.contains(point)` +- `range.contains_inclusive(offset)` ⟹ `range.contains_inclusive(point)` diff --git a/third_party/crates/text-size-1.1.1/Cargo.toml b/third_party/crates/text-size-1.1.1/Cargo.toml new file mode 100644 index 0000000..11afe90 --- /dev/null +++ b/third_party/crates/text-size-1.1.1/Cargo.toml @@ -0,0 +1,40 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "text-size" +version = "1.1.1" +authors = [ + "Aleksey Kladov ", + "Christopher Durham (CAD97) ", +] +description = "Newtypes for text offsets" +documentation = "https://docs.rs/text-size" +readme = "README.md" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-analyzer/text-size" + +[[test]] +name = "serde" +path = "tests/serde.rs" +required-features = ["serde"] + +[dependencies.serde] +version = "1.0" +optional = true +default_features = false + +[dev-dependencies.serde_test] +version = "1.0" + +[dev-dependencies.static_assertions] +version = "1.1" diff --git a/third_party/crates/text-size-1.1.1/Cargo.toml.orig b/third_party/crates/text-size-1.1.1/Cargo.toml.orig new file mode 100644 index 0000000..e456ad3 --- /dev/null +++ b/third_party/crates/text-size-1.1.1/Cargo.toml.orig @@ -0,0 +1,25 @@ +[package] +name = "text-size" +version = "1.1.1" +edition = "2018" + +authors = [ + "Aleksey Kladov ", + "Christopher Durham (CAD97) " +] +description = "Newtypes for text offsets" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-analyzer/text-size" +documentation = "https://docs.rs/text-size" + +[dependencies] +serde = { version = "1.0", optional = true, default_features = false } + +[dev-dependencies] +serde_test = "1.0" +static_assertions = "1.1" + +[[test]] +name = "serde" +path = "tests/serde.rs" +required-features = ["serde"] diff --git a/third_party/crates/text-size-1.1.1/LICENSE-APACHE b/third_party/crates/text-size-1.1.1/LICENSE-APACHE new file mode 100644 index 0000000..f47c941 --- /dev/null +++ b/third_party/crates/text-size-1.1.1/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/third_party/crates/text-size-1.1.1/LICENSE-MIT b/third_party/crates/text-size-1.1.1/LICENSE-MIT new file mode 100644 index 0000000..458723b --- /dev/null +++ b/third_party/crates/text-size-1.1.1/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/third_party/crates/text-size-1.1.1/README.md b/third_party/crates/text-size-1.1.1/README.md new file mode 100644 index 0000000..0531bfe --- /dev/null +++ b/third_party/crates/text-size-1.1.1/README.md @@ -0,0 +1,27 @@ +# text-size + +[![Build Status](https://travis-ci.org/matklad/text-size.svg?branch=master)](https://travis-ci.org/matklad/text-size) +[![Crates.io](https://img.shields.io/crates/v/text-size.svg)](https://crates.io/crates/text-size) +[![API reference](https://docs.rs/text-size/badge.svg)](https://docs.rs/text-size/) + + +A library that provides newtype wrappers for `u32` and `(u32, u32)` for use as text offsets. + +See the [docs](https://docs.rs/text-size/) for more. + +## 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/third_party/crates/text-size-1.1.1/bors.toml b/third_party/crates/text-size-1.1.1/bors.toml new file mode 100644 index 0000000..b1ca40a --- /dev/null +++ b/third_party/crates/text-size-1.1.1/bors.toml @@ -0,0 +1,6 @@ +status = [ + "Rust (ubuntu-latest)", + "Rust (windows-latest)", + "Rust (macos-latest)", +] +delete_merged_branches = true diff --git a/third_party/crates/text-size-1.1.1/src/lib.rs b/third_party/crates/text-size-1.1.1/src/lib.rs new file mode 100644 index 0000000..af89999 --- /dev/null +++ b/third_party/crates/text-size-1.1.1/src/lib.rs @@ -0,0 +1,32 @@ +//! Newtypes for working with text sizes/ranges in a more type-safe manner. +//! +//! This library can help with two things: +//! * Reducing storage requirements for offsets and ranges, under the +//! assumption that 32 bits is enough. +//! * Providing standard vocabulary types for applications where text ranges +//! are pervasive. +//! +//! However, you should not use this library simply because you work with +//! strings. In the overwhelming majority of cases, using `usize` and +//! `std::ops::Range` is better. In particular, if you are publishing a +//! library, using only std types in the interface would make it more +//! interoperable. Similarly, if you are writing something like a lexer, which +//! produces, but does not *store* text ranges, then sticking to `usize` would +//! be better. +//! +//! Minimal Supported Rust Version: latest stable. + +#![forbid(unsafe_code)] +#![warn(missing_debug_implementations, missing_docs)] + +mod range; +mod size; +mod traits; + +#[cfg(feature = "serde")] +mod serde_impls; + +pub use crate::{range::TextRange, size::TextSize, traits::TextLen}; + +#[cfg(target_pointer_width = "16")] +compile_error!("text-size assumes usize >= u32 and does not work on 16-bit targets"); diff --git a/third_party/crates/text-size-1.1.1/src/range.rs b/third_party/crates/text-size-1.1.1/src/range.rs new file mode 100644 index 0000000..ab3c50d --- /dev/null +++ b/third_party/crates/text-size-1.1.1/src/range.rs @@ -0,0 +1,456 @@ +use cmp::Ordering; + +use { + crate::TextSize, + std::{ + cmp, fmt, + ops::{Add, AddAssign, Bound, Index, IndexMut, Range, RangeBounds, Sub, SubAssign}, + }, +}; + +/// A range in text, represented as a pair of [`TextSize`][struct@TextSize]. +/// +/// It is a logic error for `start` to be greater than `end`. +#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)] +pub struct TextRange { + // Invariant: start <= end + start: TextSize, + end: TextSize, +} + +impl fmt::Debug for TextRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}..{}", self.start().raw, self.end().raw) + } +} + +impl TextRange { + /// Creates a new `TextRange` with the given `start` and `end` (`start..end`). + /// + /// # Panics + /// + /// Panics if `end < start`. + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// let start = TextSize::from(5); + /// let end = TextSize::from(10); + /// let range = TextRange::new(start, end); + /// + /// assert_eq!(range.start(), start); + /// assert_eq!(range.end(), end); + /// assert_eq!(range.len(), end - start); + /// ``` + #[inline] + pub const fn new(start: TextSize, end: TextSize) -> TextRange { + assert!(start.raw <= end.raw); + TextRange { start, end } + } + + /// Create a new `TextRange` with the given `offset` and `len` (`offset..offset + len`). + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// let text = "0123456789"; + /// + /// let offset = TextSize::from(2); + /// let length = TextSize::from(5); + /// let range = TextRange::at(offset, length); + /// + /// assert_eq!(range, TextRange::new(offset, offset + length)); + /// assert_eq!(&text[range], "23456") + /// ``` + #[inline] + pub const fn at(offset: TextSize, len: TextSize) -> TextRange { + TextRange::new(offset, TextSize::new(offset.raw + len.raw)) + } + + /// Create a zero-length range at the specified offset (`offset..offset`). + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// let point: TextSize; + /// # point = TextSize::from(3); + /// let range = TextRange::empty(point); + /// assert!(range.is_empty()); + /// assert_eq!(range, TextRange::new(point, point)); + /// ``` + #[inline] + pub const fn empty(offset: TextSize) -> TextRange { + TextRange { + start: offset, + end: offset, + } + } + + /// Create a range up to the given end (`..end`). + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// let point: TextSize; + /// # point = TextSize::from(12); + /// let range = TextRange::up_to(point); + /// + /// assert_eq!(range.len(), point); + /// assert_eq!(range, TextRange::new(0.into(), point)); + /// assert_eq!(range, TextRange::at(0.into(), point)); + /// ``` + #[inline] + pub const fn up_to(end: TextSize) -> TextRange { + TextRange { + start: TextSize::new(0), + end, + } + } +} + +/// Identity methods. +impl TextRange { + /// The start point of this range. + #[inline] + pub const fn start(self) -> TextSize { + self.start + } + + /// The end point of this range. + #[inline] + pub const fn end(self) -> TextSize { + self.end + } + + /// The size of this range. + #[inline] + pub const fn len(self) -> TextSize { + // HACK for const fn: math on primitives only + TextSize { + raw: self.end().raw - self.start().raw, + } + } + + /// Check if this range is empty. + #[inline] + pub const fn is_empty(self) -> bool { + // HACK for const fn: math on primitives only + self.start().raw == self.end().raw + } +} + +/// Manipulation methods. +impl TextRange { + /// Check if this range contains an offset. + /// + /// The end index is considered excluded. + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// let (start, end): (TextSize, TextSize); + /// # start = 10.into(); end = 20.into(); + /// let range = TextRange::new(start, end); + /// assert!(range.contains(start)); + /// assert!(!range.contains(end)); + /// ``` + #[inline] + pub fn contains(self, offset: TextSize) -> bool { + self.start() <= offset && offset < self.end() + } + + /// Check if this range contains an offset. + /// + /// The end index is considered included. + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// let (start, end): (TextSize, TextSize); + /// # start = 10.into(); end = 20.into(); + /// let range = TextRange::new(start, end); + /// assert!(range.contains_inclusive(start)); + /// assert!(range.contains_inclusive(end)); + /// ``` + #[inline] + pub fn contains_inclusive(self, offset: TextSize) -> bool { + self.start() <= offset && offset <= self.end() + } + + /// Check if this range completely contains another range. + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// let larger = TextRange::new(0.into(), 20.into()); + /// let smaller = TextRange::new(5.into(), 15.into()); + /// assert!(larger.contains_range(smaller)); + /// assert!(!smaller.contains_range(larger)); + /// + /// // a range always contains itself + /// assert!(larger.contains_range(larger)); + /// assert!(smaller.contains_range(smaller)); + /// ``` + #[inline] + pub fn contains_range(self, other: TextRange) -> bool { + self.start() <= other.start() && other.end() <= self.end() + } + + /// The range covered by both ranges, if it exists. + /// If the ranges touch but do not overlap, the output range is empty. + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// assert_eq!( + /// TextRange::intersect( + /// TextRange::new(0.into(), 10.into()), + /// TextRange::new(5.into(), 15.into()), + /// ), + /// Some(TextRange::new(5.into(), 10.into())), + /// ); + /// ``` + #[inline] + pub fn intersect(self, other: TextRange) -> Option { + let start = cmp::max(self.start(), other.start()); + let end = cmp::min(self.end(), other.end()); + if end < start { + return None; + } + Some(TextRange::new(start, end)) + } + + /// Extends the range to cover `other` as well. + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// assert_eq!( + /// TextRange::cover( + /// TextRange::new(0.into(), 5.into()), + /// TextRange::new(15.into(), 20.into()), + /// ), + /// TextRange::new(0.into(), 20.into()), + /// ); + /// ``` + #[inline] + pub fn cover(self, other: TextRange) -> TextRange { + let start = cmp::min(self.start(), other.start()); + let end = cmp::max(self.end(), other.end()); + TextRange::new(start, end) + } + + /// Extends the range to cover `other` offsets as well. + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// assert_eq!( + /// TextRange::empty(0.into()).cover_offset(20.into()), + /// TextRange::new(0.into(), 20.into()), + /// ) + /// ``` + #[inline] + pub fn cover_offset(self, offset: TextSize) -> TextRange { + self.cover(TextRange::empty(offset)) + } + + /// Add an offset to this range. + /// + /// Note that this is not appropriate for changing where a `TextRange` is + /// within some string; rather, it is for changing the reference anchor + /// that the `TextRange` is measured against. + /// + /// The unchecked version (`Add::add`) will _always_ panic on overflow, + /// in contrast to primitive integers, which check in debug mode only. + #[inline] + pub fn checked_add(self, offset: TextSize) -> Option { + Some(TextRange { + start: self.start.checked_add(offset)?, + end: self.end.checked_add(offset)?, + }) + } + + /// Subtract an offset from this range. + /// + /// Note that this is not appropriate for changing where a `TextRange` is + /// within some string; rather, it is for changing the reference anchor + /// that the `TextRange` is measured against. + /// + /// The unchecked version (`Sub::sub`) will _always_ panic on overflow, + /// in contrast to primitive integers, which check in debug mode only. + #[inline] + pub fn checked_sub(self, offset: TextSize) -> Option { + Some(TextRange { + start: self.start.checked_sub(offset)?, + end: self.end.checked_sub(offset)?, + }) + } + + /// Relative order of the two ranges (overlapping ranges are considered + /// equal). + /// + /// + /// This is useful when, for example, binary searching an array of disjoint + /// ranges. + /// + /// # Examples + /// + /// ``` + /// # use text_size::*; + /// # use std::cmp::Ordering; + /// + /// let a = TextRange::new(0.into(), 3.into()); + /// let b = TextRange::new(4.into(), 5.into()); + /// assert_eq!(a.ordering(b), Ordering::Less); + /// + /// let a = TextRange::new(0.into(), 3.into()); + /// let b = TextRange::new(3.into(), 5.into()); + /// assert_eq!(a.ordering(b), Ordering::Less); + /// + /// let a = TextRange::new(0.into(), 3.into()); + /// let b = TextRange::new(2.into(), 5.into()); + /// assert_eq!(a.ordering(b), Ordering::Equal); + /// + /// let a = TextRange::new(0.into(), 3.into()); + /// let b = TextRange::new(2.into(), 2.into()); + /// assert_eq!(a.ordering(b), Ordering::Equal); + /// + /// let a = TextRange::new(2.into(), 3.into()); + /// let b = TextRange::new(2.into(), 2.into()); + /// assert_eq!(a.ordering(b), Ordering::Greater); + /// ``` + #[inline] + pub fn ordering(self, other: TextRange) -> Ordering { + if self.end() <= other.start() { + Ordering::Less + } else if other.end() <= self.start() { + Ordering::Greater + } else { + Ordering::Equal + } + } +} + +impl Index for str { + type Output = str; + #[inline] + fn index(&self, index: TextRange) -> &str { + &self[Range::::from(index)] + } +} + +impl Index for String { + type Output = str; + #[inline] + fn index(&self, index: TextRange) -> &str { + &self[Range::::from(index)] + } +} + +impl IndexMut for str { + #[inline] + fn index_mut(&mut self, index: TextRange) -> &mut str { + &mut self[Range::::from(index)] + } +} + +impl IndexMut for String { + #[inline] + fn index_mut(&mut self, index: TextRange) -> &mut str { + &mut self[Range::::from(index)] + } +} + +impl RangeBounds for TextRange { + fn start_bound(&self) -> Bound<&TextSize> { + Bound::Included(&self.start) + } + + fn end_bound(&self) -> Bound<&TextSize> { + Bound::Excluded(&self.end) + } +} + +impl From for Range +where + T: From, +{ + #[inline] + fn from(r: TextRange) -> Self { + r.start().into()..r.end().into() + } +} + +macro_rules! ops { + (impl $Op:ident for TextRange by fn $f:ident = $op:tt) => { + impl $Op<&TextSize> for TextRange { + type Output = TextRange; + #[inline] + fn $f(self, other: &TextSize) -> TextRange { + self $op *other + } + } + impl $Op for &TextRange + where + TextRange: $Op, + { + type Output = TextRange; + #[inline] + fn $f(self, other: T) -> TextRange { + *self $op other + } + } + }; +} + +impl Add for TextRange { + type Output = TextRange; + #[inline] + fn add(self, offset: TextSize) -> TextRange { + self.checked_add(offset) + .expect("TextRange +offset overflowed") + } +} + +impl Sub for TextRange { + type Output = TextRange; + #[inline] + fn sub(self, offset: TextSize) -> TextRange { + self.checked_sub(offset) + .expect("TextRange -offset overflowed") + } +} + +ops!(impl Add for TextRange by fn add = +); +ops!(impl Sub for TextRange by fn sub = -); + +impl AddAssign for TextRange +where + TextRange: Add, +{ + #[inline] + fn add_assign(&mut self, rhs: A) { + *self = *self + rhs + } +} + +impl SubAssign for TextRange +where + TextRange: Sub, +{ + #[inline] + fn sub_assign(&mut self, rhs: S) { + *self = *self - rhs + } +} diff --git a/third_party/crates/text-size-1.1.1/src/serde_impls.rs b/third_party/crates/text-size-1.1.1/src/serde_impls.rs new file mode 100644 index 0000000..e55908b --- /dev/null +++ b/third_party/crates/text-size-1.1.1/src/serde_impls.rs @@ -0,0 +1,48 @@ +use { + crate::{TextRange, TextSize}, + serde::{de, Deserialize, Deserializer, Serialize, Serializer}, +}; + +impl Serialize for TextSize { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.raw.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for TextSize { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + u32::deserialize(deserializer).map(TextSize::from) + } +} + +impl Serialize for TextRange { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + (self.start(), self.end()).serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for TextRange { + #[allow(clippy::nonminimal_bool)] + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let (start, end) = Deserialize::deserialize(deserializer)?; + if !(start <= end) { + return Err(de::Error::custom(format!( + "invalid range: {:?}..{:?}", + start, end + ))); + } + Ok(TextRange::new(start, end)) + } +} diff --git a/third_party/crates/text-size-1.1.1/src/size.rs b/third_party/crates/text-size-1.1.1/src/size.rs new file mode 100644 index 0000000..62f2752 --- /dev/null +++ b/third_party/crates/text-size-1.1.1/src/size.rs @@ -0,0 +1,173 @@ +use { + crate::TextLen, + std::{ + convert::TryFrom, + fmt, iter, + num::TryFromIntError, + ops::{Add, AddAssign, Sub, SubAssign}, + u32, + }, +}; + +/// A measure of text length. Also, equivalently, an index into text. +/// +/// This is a UTF-8 bytes offset stored as `u32`, but +/// most clients should treat it as an opaque measure. +/// +/// For cases that need to escape `TextSize` and return to working directly +/// with primitive integers, `TextSize` can be converted losslessly to/from +/// `u32` via [`From`] conversions as well as losslessly be converted [`Into`] +/// `usize`. The `usize -> TextSize` direction can be done via [`TryFrom`]. +/// +/// These escape hatches are primarily required for unit testing and when +/// converting from UTF-8 size to another coordinate space, such as UTF-16. +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct TextSize { + pub(crate) raw: u32, +} + +impl fmt::Debug for TextSize { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.raw) + } +} + +impl TextSize { + /// Creates a new instance of `TextSize` from a raw `u32`. + #[inline] + pub const fn new(raw: u32) -> TextSize { + TextSize { raw } + } + + /// The text size of some primitive text-like object. + /// + /// Accepts `char`, `&str`, and `&String`. + /// + /// # Examples + /// + /// ```rust + /// # use text_size::*; + /// let char_size = TextSize::of('🦀'); + /// assert_eq!(char_size, TextSize::from(4)); + /// + /// let str_size = TextSize::of("rust-analyzer"); + /// assert_eq!(str_size, TextSize::from(13)); + /// ``` + #[inline] + pub fn of(text: T) -> TextSize { + text.text_len() + } +} + +/// Methods to act like a primitive integer type, where reasonably applicable. +// Last updated for parity with Rust 1.42.0. +impl TextSize { + /// Checked addition. Returns `None` if overflow occurred. + #[inline] + pub const fn checked_add(self, rhs: TextSize) -> Option { + match self.raw.checked_add(rhs.raw) { + Some(raw) => Some(TextSize { raw }), + None => None, + } + } + + /// Checked subtraction. Returns `None` if overflow occurred. + #[inline] + pub const fn checked_sub(self, rhs: TextSize) -> Option { + match self.raw.checked_sub(rhs.raw) { + Some(raw) => Some(TextSize { raw }), + None => None, + } + } +} + +impl From for TextSize { + #[inline] + fn from(raw: u32) -> Self { + TextSize { raw } + } +} + +impl From for u32 { + #[inline] + fn from(value: TextSize) -> Self { + value.raw + } +} + +impl TryFrom for TextSize { + type Error = TryFromIntError; + #[inline] + fn try_from(value: usize) -> Result { + Ok(u32::try_from(value)?.into()) + } +} + +impl From for usize { + #[inline] + fn from(value: TextSize) -> Self { + value.raw as usize + } +} + +macro_rules! ops { + (impl $Op:ident for TextSize by fn $f:ident = $op:tt) => { + impl $Op for TextSize { + type Output = TextSize; + #[inline] + fn $f(self, other: TextSize) -> TextSize { + TextSize { raw: self.raw $op other.raw } + } + } + impl $Op<&TextSize> for TextSize { + type Output = TextSize; + #[inline] + fn $f(self, other: &TextSize) -> TextSize { + self $op *other + } + } + impl $Op for &TextSize + where + TextSize: $Op, + { + type Output = TextSize; + #[inline] + fn $f(self, other: T) -> TextSize { + *self $op other + } + } + }; +} + +ops!(impl Add for TextSize by fn add = +); +ops!(impl Sub for TextSize by fn sub = -); + +impl AddAssign for TextSize +where + TextSize: Add, +{ + #[inline] + fn add_assign(&mut self, rhs: A) { + *self = *self + rhs + } +} + +impl SubAssign for TextSize +where + TextSize: Sub, +{ + #[inline] + fn sub_assign(&mut self, rhs: S) { + *self = *self - rhs + } +} + +impl iter::Sum for TextSize +where + TextSize: Add, +{ + #[inline] + fn sum>(iter: I) -> TextSize { + iter.fold(0.into(), Add::add) + } +} diff --git a/third_party/crates/text-size-1.1.1/src/traits.rs b/third_party/crates/text-size-1.1.1/src/traits.rs new file mode 100644 index 0000000..7de20dc --- /dev/null +++ b/third_party/crates/text-size-1.1.1/src/traits.rs @@ -0,0 +1,36 @@ +use {crate::TextSize, std::convert::TryInto}; + +use priv_in_pub::Sealed; +mod priv_in_pub { + pub trait Sealed {} +} + +/// Primitives with a textual length that can be passed to [`TextSize::of`]. +pub trait TextLen: Copy + Sealed { + /// The textual length of this primitive. + fn text_len(self) -> TextSize; +} + +impl Sealed for &'_ str {} +impl TextLen for &'_ str { + #[inline] + fn text_len(self) -> TextSize { + self.len().try_into().unwrap() + } +} + +impl Sealed for &'_ String {} +impl TextLen for &'_ String { + #[inline] + fn text_len(self) -> TextSize { + self.as_str().text_len() + } +} + +impl Sealed for char {} +impl TextLen for char { + #[inline] + fn text_len(self) -> TextSize { + (self.len_utf8() as u32).into() + } +} diff --git a/third_party/crates/text-size-1.1.1/tests/auto_traits.rs b/third_party/crates/text-size-1.1.1/tests/auto_traits.rs new file mode 100644 index 0000000..636f92a --- /dev/null +++ b/third_party/crates/text-size-1.1.1/tests/auto_traits.rs @@ -0,0 +1,18 @@ +use { + static_assertions::*, + std::{ + fmt::Debug, + hash::Hash, + marker::{Send, Sync}, + panic::{RefUnwindSafe, UnwindSafe}, + }, + text_size::*, +}; + +// auto traits +assert_impl_all!(TextSize: Send, Sync, Unpin, UnwindSafe, RefUnwindSafe); +assert_impl_all!(TextRange: Send, Sync, Unpin, UnwindSafe, RefUnwindSafe); + +// common traits +assert_impl_all!(TextSize: Copy, Debug, Default, Hash, Ord); +assert_impl_all!(TextRange: Copy, Debug, Default, Hash, Eq); diff --git a/third_party/crates/text-size-1.1.1/tests/constructors.rs b/third_party/crates/text-size-1.1.1/tests/constructors.rs new file mode 100644 index 0000000..ab9a5f0 --- /dev/null +++ b/third_party/crates/text-size-1.1.1/tests/constructors.rs @@ -0,0 +1,24 @@ +use text_size::TextSize; + +#[derive(Copy, Clone)] +struct BadRope<'a>(&'a [&'a str]); + +impl BadRope<'_> { + fn text_len(self) -> TextSize { + self.0.iter().copied().map(TextSize::of).sum() + } +} + +#[test] +fn main() { + let x: char = 'c'; + let _ = TextSize::of(x); + + let x: &str = "hello"; + let _ = TextSize::of(x); + + let x: &String = &"hello".into(); + let _ = TextSize::of(x); + + let _ = BadRope(&[""]).text_len(); +} diff --git a/third_party/crates/text-size-1.1.1/tests/indexing.rs b/third_party/crates/text-size-1.1.1/tests/indexing.rs new file mode 100644 index 0000000..dfea5ee --- /dev/null +++ b/third_party/crates/text-size-1.1.1/tests/indexing.rs @@ -0,0 +1,8 @@ +use text_size::*; + +#[test] +fn main() { + let range = TextRange::default(); + _ = &""[range]; + _ = &String::new()[range]; +} diff --git a/third_party/crates/text-size-1.1.1/tests/main.rs b/third_party/crates/text-size-1.1.1/tests/main.rs new file mode 100644 index 0000000..0501c90 --- /dev/null +++ b/third_party/crates/text-size-1.1.1/tests/main.rs @@ -0,0 +1,76 @@ +use {std::ops, text_size::*}; + +fn size(x: u32) -> TextSize { + TextSize::from(x) +} + +fn range(x: ops::Range) -> TextRange { + TextRange::new(x.start.into(), x.end.into()) +} + +#[test] +fn sum() { + let xs: Vec = vec![size(0), size(1), size(2)]; + assert_eq!(xs.iter().sum::(), size(3)); + assert_eq!(xs.into_iter().sum::(), size(3)); +} + +#[test] +fn math() { + assert_eq!(size(10) + size(5), size(15)); + assert_eq!(size(10) - size(5), size(5)); +} + +#[test] +fn checked_math() { + assert_eq!(size(1).checked_add(size(1)), Some(size(2))); + assert_eq!(size(1).checked_sub(size(1)), Some(size(0))); + assert_eq!(size(1).checked_sub(size(2)), None); + assert_eq!(size(!0).checked_add(size(1)), None); +} + +#[test] +#[rustfmt::skip] +fn contains() { + assert!( range(2..4).contains_range(range(2..3))); + assert!( ! range(2..4).contains_range(range(1..3))); +} + +#[test] +fn intersect() { + assert_eq!(range(1..2).intersect(range(2..3)), Some(range(2..2))); + assert_eq!(range(1..5).intersect(range(2..3)), Some(range(2..3))); + assert_eq!(range(1..2).intersect(range(3..4)), None); +} + +#[test] +fn cover() { + assert_eq!(range(1..2).cover(range(2..3)), range(1..3)); + assert_eq!(range(1..5).cover(range(2..3)), range(1..5)); + assert_eq!(range(1..2).cover(range(4..5)), range(1..5)); +} + +#[test] +fn cover_offset() { + assert_eq!(range(1..3).cover_offset(size(0)), range(0..3)); + assert_eq!(range(1..3).cover_offset(size(1)), range(1..3)); + assert_eq!(range(1..3).cover_offset(size(2)), range(1..3)); + assert_eq!(range(1..3).cover_offset(size(3)), range(1..3)); + assert_eq!(range(1..3).cover_offset(size(4)), range(1..4)); +} + +#[test] +#[rustfmt::skip] +fn contains_point() { + assert!( ! range(1..3).contains(size(0))); + assert!( range(1..3).contains(size(1))); + assert!( range(1..3).contains(size(2))); + assert!( ! range(1..3).contains(size(3))); + assert!( ! range(1..3).contains(size(4))); + + assert!( ! range(1..3).contains_inclusive(size(0))); + assert!( range(1..3).contains_inclusive(size(1))); + assert!( range(1..3).contains_inclusive(size(2))); + assert!( range(1..3).contains_inclusive(size(3))); + assert!( ! range(1..3).contains_inclusive(size(4))); +} diff --git a/third_party/crates/text-size-1.1.1/tests/serde.rs b/third_party/crates/text-size-1.1.1/tests/serde.rs new file mode 100644 index 0000000..fc0d28b --- /dev/null +++ b/third_party/crates/text-size-1.1.1/tests/serde.rs @@ -0,0 +1,79 @@ +use {serde_test::*, std::ops, text_size::*}; + +fn size(x: u32) -> TextSize { + TextSize::from(x) +} + +fn range(x: ops::Range) -> TextRange { + TextRange::new(x.start.into(), x.end.into()) +} + +#[test] +fn size_serialization() { + assert_tokens(&size(00), &[Token::U32(00)]); + assert_tokens(&size(10), &[Token::U32(10)]); + assert_tokens(&size(20), &[Token::U32(20)]); + assert_tokens(&size(30), &[Token::U32(30)]); +} + +#[test] +fn range_serialization() { + assert_tokens( + &range(00..10), + &[ + Token::Tuple { len: 2 }, + Token::U32(00), + Token::U32(10), + Token::TupleEnd, + ], + ); + assert_tokens( + &range(10..20), + &[ + Token::Tuple { len: 2 }, + Token::U32(10), + Token::U32(20), + Token::TupleEnd, + ], + ); + assert_tokens( + &range(20..30), + &[ + Token::Tuple { len: 2 }, + Token::U32(20), + Token::U32(30), + Token::TupleEnd, + ], + ); + assert_tokens( + &range(30..40), + &[ + Token::Tuple { len: 2 }, + Token::U32(30), + Token::U32(40), + Token::TupleEnd, + ], + ); +} + +#[test] +fn invalid_range_deserialization() { + assert_tokens::( + &range(62..92), + &[ + Token::Tuple { len: 2 }, + Token::U32(62), + Token::U32(92), + Token::TupleEnd, + ], + ); + assert_de_tokens_error::( + &[ + Token::Tuple { len: 2 }, + Token::U32(92), + Token::U32(62), + Token::TupleEnd, + ], + "invalid range: 92..62", + ); +}