From ae6000336f3b83de799295a9df53f01d1a4757f0 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Sun, 24 Sep 2023 17:42:17 +0200 Subject: [PATCH] Implement memory limits in Global allocator --- .github/workflows/ci.yml | 19 +- Cargo.toml | 4 +- README.md | 4 +- UPGRADING.md | 4 +- benches/benches/bench_main.rs | 6 +- benches/benches/benchmarks/aoc_2020_19b.rs | 2 +- benches/benches/benchmarks/aoc_2020_1a.rs | 2 +- benches/benches/benchmarks/aoc_2020_1b.rs | 2 +- benches/benches/benchmarks/brainfuck.rs | 3 +- crates/rune-alloc-macros/Cargo.toml | 22 + crates/rune-alloc-macros/src/context.rs | 68 ++ crates/rune-alloc-macros/src/lib.rs | 47 ++ crates/rune-alloc-macros/src/try_clone.rs | 255 +++++++ crates/rune-alloc/Cargo.toml | 7 +- crates/rune-alloc/src/alloc/allocator.rs | 90 +-- crates/rune-alloc/src/alloc/borrow/mod.rs | 2 - .../src/alloc/borrow/try_to_owned.rs | 43 -- crates/rune-alloc/src/alloc/global.rs | 85 +++ crates/rune-alloc/src/alloc/mod.rs | 113 +-- crates/rune-alloc/src/alloc/slice.rs | 133 ---- crates/rune-alloc/src/alloc/testing.rs | 75 -- crates/rune-alloc/src/borrow/mod.rs | 406 ++++++++++ crates/rune-alloc/src/{alloc => }/boxed.rs | 254 ++++++- .../src/{alloc => }/btree/append.rs | 8 +- .../src/{alloc => }/btree/borrow.rs | 0 .../rune-alloc/src/{alloc => }/btree/fix.rs | 4 +- .../rune-alloc/src/{alloc => }/btree/map.rs | 45 +- .../src/{alloc => }/btree/map/entry.rs | 26 +- .../src/{alloc => }/btree/map/tests.rs | 14 +- .../rune-alloc/src/{alloc => }/btree/mem.rs | 2 +- .../src/{alloc => }/btree/merge_iter.rs | 0 .../rune-alloc/src/{alloc => }/btree/mod.rs | 0 .../src/{alloc => }/btree/navigate.rs | 0 .../rune-alloc/src/{alloc => }/btree/node.rs | 0 .../src/{alloc => }/btree/node/tests.rs | 2 +- .../src/{alloc => }/btree/remove.rs | 4 +- .../src/{alloc => }/btree/search.rs | 0 .../rune-alloc/src/{alloc => }/btree/set.rs | 31 +- .../src/{alloc => }/btree/set/tests.rs | 2 +- .../src/{alloc => }/btree/set_val.rs | 3 +- .../rune-alloc/src/{alloc => }/btree/split.rs | 0 .../src/{alloc/try_clone.rs => clone.rs} | 55 +- crates/rune-alloc/src/error.rs | 77 ++ crates/rune-alloc/src/fmt.rs | 87 ++- .../src/{alloc => }/hashbrown/map.rs | 66 +- .../src/{alloc => }/hashbrown/mod.rs | 11 +- .../src/{alloc => }/hashbrown/raw/bitmask.rs | 0 .../src/{alloc => }/hashbrown/raw/generic.rs | 0 .../src/{alloc => }/hashbrown/raw/mod.rs | 15 +- .../src/{alloc => }/hashbrown/raw/neon.rs | 0 .../src/{alloc => }/hashbrown/raw/sse2.rs | 0 .../src/{alloc => }/hashbrown/scopeguard.rs | 0 crates/rune-alloc/src/hashbrown/serde.rs | 227 ++++++ .../src/{alloc => }/hashbrown/set.rs | 17 +- crates/rune-alloc/src/iter/ext.rs | 76 +- crates/rune-alloc/src/iter/join.rs | 10 + crates/rune-alloc/src/iter/mod.rs | 12 + crates/rune-alloc/src/iter/try_cloned.rs | 36 + .../src/{alloc => iter}/try_extend.rs | 5 +- .../src/{alloc => iter}/try_from_iterator.rs | 3 +- crates/rune-alloc/src/lib.rs | 88 ++- crates/rune-alloc/src/limit.rs | 121 +++ crates/rune-alloc/src/limit/no_std.rs | 23 + crates/rune-alloc/src/limit/std.rs | 37 + crates/rune-alloc/src/no_std.rs | 41 ++ crates/rune-alloc/src/option/ext.rs | 35 + crates/rune-alloc/src/option/mod.rs | 2 + .../src/no_std => rune-alloc/src}/path.rs | 66 +- crates/rune-alloc/src/public_macros.rs | 54 +- crates/rune-alloc/src/{alloc => }/raw_vec.rs | 9 +- crates/rune-alloc/src/serde/de.rs | 176 +++++ crates/rune-alloc/src/serde/mod.rs | 2 + crates/rune-alloc/src/serde/ser.rs | 47 ++ crates/rune-alloc/src/slice.rs | 132 ++++ crates/rune-alloc/src/{alloc => }/str.rs | 11 +- .../src/{alloc/string.rs => string/mod.rs} | 305 ++++++-- .../src/{alloc => }/string/serde.rs | 27 +- .../src/{alloc => }/string/try_to_string.rs | 9 +- crates/rune-alloc/src/testing/crash_test.rs | 3 +- crates/rune-alloc/src/testing/mod.rs | 77 ++ crates/rune-alloc/src/tests.rs | 3 +- .../rune-alloc/src/{alloc => }/vec/drain.rs | 3 +- .../src/{alloc => }/vec/into_iter.rs | 5 +- .../rune-alloc/src/{alloc => }/vec/is_zero.rs | 0 crates/rune-alloc/src/{alloc => }/vec/mod.rs | 124 ++-- .../src/{alloc => }/vec/partial_eq.rs | 2 + .../src/{alloc => }/vec/set_len_on_drop.rs | 0 .../src/{alloc => }/vec/spec_extend.rs | 5 +- .../src/{alloc => }/vec/spec_from_elem.rs | 6 +- .../rune-alloc/src/{alloc => }/vec/splice.rs | 3 +- .../src/{alloc => }/vec_deque/drain.rs | 0 .../src/{alloc => }/vec_deque/into_iter.rs | 4 +- .../src/{alloc => }/vec_deque/iter.rs | 0 .../src/{alloc => }/vec_deque/iter_mut.rs | 0 .../src/{alloc => }/vec_deque/macros.rs | 0 .../src/{alloc => }/vec_deque/mod.rs | 52 +- .../src/{alloc => }/vec_deque/raw_iter.rs | 0 crates/rune-core/Cargo.toml | 5 +- crates/rune-core/src/error.rs | 4 +- crates/rune-core/src/hash.rs | 13 +- crates/rune-core/src/hash/to_type_hash.rs | 15 +- crates/rune-core/src/item.rs | 4 + crates/rune-core/src/item/component.rs | 29 +- crates/rune-core/src/item/component_ref.rs | 12 +- crates/rune-core/src/item/internal.rs | 33 +- crates/rune-core/src/item/into_component.rs | 84 ++- crates/rune-core/src/item/item.rs | 94 ++- crates/rune-core/src/item/item_buf.rs | 301 +++++--- crates/rune-core/src/item/serde.rs | 70 ++ crates/rune-core/src/item/tests.rs | 80 +- crates/rune-core/src/lib.rs | 8 +- crates/rune-core/src/protocol.rs | 20 +- crates/rune-core/src/raw_str.rs | 9 + crates/rune-core/src/type_of.rs | 5 +- crates/rune-macros/Cargo.toml | 2 +- crates/rune-macros/src/any.rs | 16 +- crates/rune-macros/src/context.rs | 2 + crates/rune-macros/src/function.rs | 296 +++++++- crates/rune-macros/src/hash.rs | 11 +- crates/rune-macros/src/lib.rs | 16 +- crates/rune-macros/src/macro_.rs | 8 +- crates/rune-macros/src/module.rs | 14 +- crates/rune-macros/src/quote.rs | 8 +- crates/rune-macros/src/quote/inner.rs | 4 +- crates/rune-macros/src/to_tokens.rs | 56 +- crates/rune-modules/src/experiments.rs | 9 +- .../src/experiments/stringy_math_macro.rs | 2 +- crates/rune-modules/src/fs.rs | 4 +- crates/rune-modules/src/http.rs | 8 +- crates/rune-modules/src/json.rs | 65 +- crates/rune-modules/src/lib.rs | 29 +- crates/rune-modules/src/process.rs | 33 +- crates/rune-modules/src/rand.rs | 8 +- crates/rune-modules/src/signal.rs | 4 +- crates/rune-modules/src/time.rs | 4 +- crates/rune-modules/src/toml.rs | 127 +++- crates/rune-wasm/src/http.rs | 2 +- crates/rune-wasm/src/lib.rs | 6 +- crates/rune-wasm/src/time.rs | 2 +- crates/rune/Cargo.toml | 13 +- crates/rune/README.md | 4 +- crates/rune/src/any.rs | 9 +- crates/rune/src/ast.rs | 26 +- crates/rune/src/ast/attribute.rs | 7 +- crates/rune/src/ast/block.rs | 8 +- crates/rune/src/ast/condition.rs | 2 +- crates/rune/src/ast/expr.rs | 36 +- crates/rune/src/ast/expr_assign.rs | 2 +- crates/rune/src/ast/expr_await.rs | 2 +- crates/rune/src/ast/expr_binary.rs | 5 +- crates/rune/src/ast/expr_block.rs | 2 +- crates/rune/src/ast/expr_break.rs | 2 +- crates/rune/src/ast/expr_call.rs | 2 +- crates/rune/src/ast/expr_closure.rs | 6 +- crates/rune/src/ast/expr_continue.rs | 2 +- crates/rune/src/ast/expr_empty.rs | 2 +- crates/rune/src/ast/expr_field_access.rs | 4 +- crates/rune/src/ast/expr_for.rs | 4 +- crates/rune/src/ast/expr_group.rs | 2 +- crates/rune/src/ast/expr_if.rs | 6 +- crates/rune/src/ast/expr_index.rs | 2 +- crates/rune/src/ast/expr_let.rs | 8 +- crates/rune/src/ast/expr_lit.rs | 2 +- crates/rune/src/ast/expr_loop.rs | 2 +- crates/rune/src/ast/expr_match.rs | 8 +- crates/rune/src/ast/expr_object.rs | 11 +- crates/rune/src/ast/expr_range.rs | 4 +- crates/rune/src/ast/expr_return.rs | 2 +- crates/rune/src/ast/expr_select.rs | 10 +- crates/rune/src/ast/expr_try.rs | 2 +- crates/rune/src/ast/expr_tuple.rs | 2 +- crates/rune/src/ast/expr_unary.rs | 9 +- crates/rune/src/ast/expr_vec.rs | 2 +- crates/rune/src/ast/expr_while.rs | 2 +- crates/rune/src/ast/expr_yield.rs | 2 +- crates/rune/src/ast/fields.rs | 2 +- crates/rune/src/ast/file.rs | 16 +- crates/rune/src/ast/fn_arg.rs | 2 +- crates/rune/src/ast/generated.rs | 695 ++++++++++-------- crates/rune/src/ast/grouped.rs | 10 +- crates/rune/src/ast/ident.rs | 23 +- crates/rune/src/ast/item.rs | 2 +- crates/rune/src/ast/item_const.rs | 2 +- crates/rune/src/ast/item_enum.rs | 4 +- crates/rune/src/ast/item_fn.rs | 2 +- crates/rune/src/ast/item_impl.rs | 6 +- crates/rune/src/ast/item_mod.rs | 6 +- crates/rune/src/ast/item_struct.rs | 4 +- crates/rune/src/ast/item_use.rs | 6 +- crates/rune/src/ast/label.rs | 23 +- crates/rune/src/ast/lit.rs | 15 +- crates/rune/src/ast/lit_bool.rs | 11 +- crates/rune/src/ast/lit_byte.rs | 11 +- crates/rune/src/ast/lit_byte_str.rs | 20 +- crates/rune/src/ast/lit_char.rs | 11 +- crates/rune/src/ast/lit_number.rs | 22 +- crates/rune/src/ast/lit_str.rs | 20 +- crates/rune/src/ast/local.rs | 2 +- crates/rune/src/ast/macro_call.rs | 4 +- crates/rune/src/ast/macro_utils.rs | 7 +- crates/rune/src/ast/pat.rs | 32 +- crates/rune/src/ast/path.rs | 41 +- crates/rune/src/ast/prelude.rs | 3 +- crates/rune/src/ast/span.rs | 10 +- crates/rune/src/ast/spanned.rs | 19 + crates/rune/src/ast/stmt.rs | 11 +- crates/rune/src/ast/token.rs | 49 +- crates/rune/src/ast/vis.rs | 7 +- crates/rune/src/build.rs | 108 ++- crates/rune/src/cli.rs | 43 +- crates/rune/src/cli/benches.rs | 2 +- crates/rune/src/cli/check.rs | 4 +- crates/rune/src/cli/doc.rs | 8 +- crates/rune/src/cli/format.rs | 2 +- crates/rune/src/cli/loader.rs | 24 +- crates/rune/src/cli/run.rs | 2 +- crates/rune/src/cli/tests.rs | 17 +- crates/rune/src/cli/visitor.rs | 8 +- crates/rune/src/compile.rs | 1 + crates/rune/src/compile/assembly.rs | 122 +-- crates/rune/src/compile/compile.rs | 75 +- crates/rune/src/compile/compile_visitor.rs | 20 +- crates/rune/src/compile/context.rs | 174 ++--- crates/rune/src/compile/context_error.rs | 20 +- crates/rune/src/compile/docs.rs | 24 +- crates/rune/src/compile/error.rs | 156 ++-- crates/rune/src/compile/ir.rs | 75 +- crates/rune/src/compile/ir/compiler.rs | 69 +- crates/rune/src/compile/ir/eval.rs | 45 +- crates/rune/src/compile/ir/interpreter.rs | 60 +- crates/rune/src/compile/ir/scopes.rs | 65 +- crates/rune/src/compile/ir/value.rs | 45 +- crates/rune/src/compile/location.rs | 5 +- crates/rune/src/compile/meta.rs | 41 +- crates/rune/src/compile/meta_info.rs | 14 +- crates/rune/src/compile/named.rs | 3 +- crates/rune/src/compile/names.rs | 83 +-- crates/rune/src/compile/pool.rs | 73 +- crates/rune/src/compile/prelude.rs | 76 +- crates/rune/src/compile/source_loader.rs | 26 +- crates/rune/src/compile/unit_builder.rs | 338 +++++---- crates/rune/src/compile/v1/assemble.rs | 406 +++++----- crates/rune/src/compile/v1/loops.rs | 18 +- crates/rune/src/compile/v1/scopes.rs | 43 +- crates/rune/src/compile/with_span.rs | 32 +- crates/rune/src/diagnostics.rs | 4 +- crates/rune/src/doc/artifacts.rs | 14 +- crates/rune/src/doc/build.rs | 303 ++++---- crates/rune/src/doc/build/enum_.rs | 7 +- crates/rune/src/doc/build/js.rs | 10 +- crates/rune/src/doc/build/markdown.rs | 50 +- crates/rune/src/doc/build/type_.rs | 54 +- crates/rune/src/doc/context.rs | 44 +- crates/rune/src/doc/templating.rs | 23 +- crates/rune/src/doc/visitor.rs | 64 +- crates/rune/src/exported_macros.rs | 30 + crates/rune/src/fmt.rs | 3 +- crates/rune/src/fmt/error.rs | 10 + crates/rune/src/fmt/indent_writer.rs | 66 +- crates/rune/src/fmt/indent_writer/tests.rs | 19 +- crates/rune/src/fmt/printer.rs | 14 +- crates/rune/src/fmt/tests.rs | 71 +- crates/rune/src/hash.rs | 2 +- crates/rune/src/hashbrown/table.rs | 23 +- crates/rune/src/hir/arena.rs | 10 +- crates/rune/src/hir/hir.rs | 158 ++-- crates/rune/src/hir/interpreter.rs | 3 +- crates/rune/src/hir/lowering.rs | 149 ++-- crates/rune/src/hir/scopes.rs | 61 +- crates/rune/src/indexing.rs | 29 +- crates/rune/src/indexing/index.rs | 185 ++--- crates/rune/src/indexing/items.rs | 34 +- crates/rune/src/indexing/scopes.rs | 36 +- crates/rune/src/languageserver.rs | 18 +- crates/rune/src/languageserver/completion.rs | 78 +- crates/rune/src/languageserver/state.rs | 304 +++++--- crates/rune/src/languageserver/url.rs | 18 +- crates/rune/src/lib.rs | 58 +- crates/rune/src/macros.rs | 15 +- crates/rune/src/macros/format_args.rs | 127 ++-- crates/rune/src/macros/into_lit.rs | 43 +- crates/rune/src/macros/macro_compiler.rs | 7 +- crates/rune/src/macros/macro_context.rs | 266 +++---- crates/rune/src/macros/quote_fn.rs | 28 +- crates/rune/src/macros/storage.rs | 49 +- crates/rune/src/macros/token_stream.rs | 95 ++- crates/rune/src/module.rs | 116 +-- crates/rune/src/module/function_meta.rs | 155 ++-- crates/rune/src/module/module.rs | 233 +++--- crates/rune/src/modules/any.rs | 4 +- crates/rune/src/modules/bytes.rs | 45 +- crates/rune/src/modules/capture_io.rs | 2 +- crates/rune/src/modules/char.rs | 2 +- crates/rune/src/modules/cmp.rs | 10 +- crates/rune/src/modules/collections.rs | 2 +- .../rune/src/modules/collections/hash_map.rs | 6 +- .../rune/src/modules/collections/hash_set.rs | 16 +- .../rune/src/modules/collections/vec_deque.rs | 16 +- crates/rune/src/modules/core.rs | 23 +- crates/rune/src/modules/disable_io.rs | 2 +- crates/rune/src/modules/f64.rs | 4 +- crates/rune/src/modules/fmt.rs | 4 +- crates/rune/src/modules/future.rs | 6 +- crates/rune/src/modules/generator.rs | 2 +- crates/rune/src/modules/hash.rs | 2 +- crates/rune/src/modules/i64.rs | 6 +- crates/rune/src/modules/io.rs | 12 +- crates/rune/src/modules/iter.rs | 2 +- crates/rune/src/modules/macros.rs | 16 +- crates/rune/src/modules/mem.rs | 2 +- crates/rune/src/modules/num.rs | 2 +- crates/rune/src/modules/object.rs | 28 +- crates/rune/src/modules/ops.rs | 4 +- crates/rune/src/modules/option.rs | 2 +- crates/rune/src/modules/result.rs | 8 +- crates/rune/src/modules/stream.rs | 2 +- crates/rune/src/modules/string.rs | 18 +- crates/rune/src/modules/test.rs | 19 +- crates/rune/src/modules/tuple.rs | 4 +- crates/rune/src/modules/vec.rs | 6 +- crates/rune/src/no_std/anyhow.rs | 23 - crates/rune/src/no_std/mod.rs | 35 - crates/rune/src/params.rs | 23 +- crates/rune/src/parse/id.rs | 11 +- crates/rune/src/parse/parse.rs | 7 +- crates/rune/src/parse/parser.rs | 2 +- crates/rune/src/parse/peek.rs | 3 +- crates/rune/src/query.rs | 26 +- crates/rune/src/query/query.rs | 336 +++++---- crates/rune/src/runtime/access.rs | 10 +- crates/rune/src/runtime/budget.rs | 2 +- crates/rune/src/runtime/budget/std.rs | 4 +- crates/rune/src/runtime/bytes.rs | 157 +++- crates/rune/src/runtime/call.rs | 5 +- crates/rune/src/runtime/const_value.rs | 89 +-- crates/rune/src/runtime/debug.rs | 14 +- crates/rune/src/runtime/fmt.rs | 20 +- crates/rune/src/runtime/format.rs | 6 +- crates/rune/src/runtime/from_value.rs | 6 +- crates/rune/src/runtime/function.rs | 33 +- crates/rune/src/runtime/generator_state.rs | 2 +- crates/rune/src/runtime/inst.rs | 32 +- crates/rune/src/runtime/iterator.rs | 4 +- crates/rune/src/runtime/label.rs | 9 +- crates/rune/src/runtime/object.rs | 17 +- crates/rune/src/runtime/protocol.rs | 11 +- crates/rune/src/runtime/range.rs | 2 +- crates/rune/src/runtime/range_from.rs | 2 +- crates/rune/src/runtime/range_full.rs | 2 +- crates/rune/src/runtime/range_inclusive.rs | 2 +- crates/rune/src/runtime/range_to.rs | 2 +- crates/rune/src/runtime/range_to_inclusive.rs | 2 +- crates/rune/src/runtime/runtime_context.rs | 4 +- crates/rune/src/runtime/shared.rs | 45 +- crates/rune/src/runtime/stack.rs | 37 +- crates/rune/src/runtime/static_string.rs | 12 +- crates/rune/src/runtime/static_type.rs | 9 +- crates/rune/src/runtime/to_value.rs | 14 +- crates/rune/src/runtime/tuple.rs | 29 +- crates/rune/src/runtime/type_info.rs | 7 +- crates/rune/src/runtime/unit.rs | 25 +- crates/rune/src/runtime/unit/byte_code.rs | 16 +- crates/rune/src/runtime/unit/storage.rs | 37 +- crates/rune/src/runtime/value.rs | 6 +- crates/rune/src/runtime/value/serde.rs | 11 +- crates/rune/src/runtime/vec.rs | 35 +- crates/rune/src/runtime/vm.rs | 57 +- crates/rune/src/runtime/vm_call.rs | 2 +- crates/rune/src/runtime/vm_error.rs | 28 +- crates/rune/src/runtime/vm_execution.rs | 6 +- crates/rune/src/shared/consts.rs | 15 +- crates/rune/src/source.rs | 2 +- crates/rune/src/sources.rs | 29 +- crates/rune/src/support.rs | 149 ++++ crates/rune/src/testing.rs | 11 +- crates/rune/src/tests.rs | 38 +- crates/rune/src/tests/attribute.rs | 52 +- crates/rune/src/tests/bug_326.rs | 6 +- crates/rune/src/tests/bug_344.rs | 8 +- crates/rune/src/tests/compiler_docs.rs | 22 +- crates/rune/src/tests/compiler_patterns.rs | 11 +- crates/rune/src/tests/custom_macros.rs | 41 +- crates/rune/src/tests/external_constructor.rs | 49 +- crates/rune/src/tests/external_generic.rs | 4 +- crates/rune/src/tests/external_ops.rs | 16 +- crates/rune/src/tests/getter_setter.rs | 2 +- crates/rune/src/tests/macros.rs | 14 +- crates/rune/src/tests/quote.rs | 51 +- crates/rune/src/tests/range.rs | 8 +- crates/rune/src/tests/reference_error.rs | 2 +- crates/rune/src/tests/rename_type.rs | 6 +- crates/rune/src/tests/type_name_native.rs | 2 +- crates/rune/src/tests/unit_constants.rs | 6 +- crates/rune/src/worker.rs | 148 ++-- crates/rune/src/worker/import.rs | 48 +- crates/rune/src/worker/task.rs | 3 +- crates/rune/src/worker/wildcard_import.rs | 24 +- crates/rune/src/workspace/build.rs | 7 +- crates/rune/src/workspace/diagnostics.rs | 2 +- crates/rune/src/workspace/error.rs | 58 +- crates/rune/src/workspace/manifest.rs | 150 ++-- crates/rune/src/workspace/source_loader.rs | 3 +- editors/code/README.md | 4 +- examples/examples/checked_add_assign.rs | 5 +- examples/examples/concat_idents.rs | 9 +- examples/examples/custom_instance_fn.rs | 7 +- examples/examples/custom_mul.rs | 7 +- examples/examples/external_enum.rs | 8 +- examples/examples/external_struct.rs | 8 +- examples/examples/function_hash.rs | 5 +- examples/examples/minimal.rs | 5 +- examples/examples/native_function.rs | 5 +- examples/examples/object.rs | 5 +- examples/examples/parsing_in_macro.rs | 15 +- examples/examples/proxy.rs | 5 +- examples/examples/references.rs | 5 +- examples/examples/rune_function.rs | 5 +- examples/examples/rune_function_macro.rs | 8 +- examples/examples/simple_external.rs | 8 +- examples/examples/tokio_spawn.rs | 7 +- examples/examples/tuple.rs | 5 +- examples/examples/vec_args.rs | 10 +- examples/examples/vec_tuple.rs | 5 +- examples/examples/vector.rs | 5 +- no-std-examples/.gitignore | 1 + no-std-examples/Cargo.lock | 484 ++++++++++++ no-std-examples/Cargo.toml | 13 + no-std-examples/examples/no_std_minimal.rs | 67 +- tools/generate/Cargo.toml | 2 +- tools/generate/src/main.rs | 16 +- 430 files changed, 10246 insertions(+), 5229 deletions(-) create mode 100644 crates/rune-alloc-macros/Cargo.toml create mode 100644 crates/rune-alloc-macros/src/context.rs create mode 100644 crates/rune-alloc-macros/src/lib.rs create mode 100644 crates/rune-alloc-macros/src/try_clone.rs delete mode 100644 crates/rune-alloc/src/alloc/borrow/mod.rs delete mode 100644 crates/rune-alloc/src/alloc/borrow/try_to_owned.rs create mode 100644 crates/rune-alloc/src/alloc/global.rs delete mode 100644 crates/rune-alloc/src/alloc/slice.rs delete mode 100644 crates/rune-alloc/src/alloc/testing.rs create mode 100644 crates/rune-alloc/src/borrow/mod.rs rename crates/rune-alloc/src/{alloc => }/boxed.rs (71%) rename crates/rune-alloc/src/{alloc => }/btree/append.rs (99%) rename crates/rune-alloc/src/{alloc => }/btree/borrow.rs (100%) rename crates/rune-alloc/src/{alloc => }/btree/fix.rs (100%) rename crates/rune-alloc/src/{alloc => }/btree/map.rs (99%) rename crates/rune-alloc/src/{alloc => }/btree/map/entry.rs (96%) rename crates/rune-alloc/src/{alloc => }/btree/map/tests.rs (99%) rename crates/rune-alloc/src/{alloc => }/btree/mem.rs (96%) rename crates/rune-alloc/src/{alloc => }/btree/merge_iter.rs (100%) rename crates/rune-alloc/src/{alloc => }/btree/mod.rs (100%) rename crates/rune-alloc/src/{alloc => }/btree/navigate.rs (100%) rename crates/rune-alloc/src/{alloc => }/btree/node.rs (100%) rename crates/rune-alloc/src/{alloc => }/btree/node/tests.rs (99%) rename crates/rune-alloc/src/{alloc => }/btree/remove.rs (100%) rename crates/rune-alloc/src/{alloc => }/btree/search.rs (100%) rename crates/rune-alloc/src/{alloc => }/btree/set.rs (98%) rename crates/rune-alloc/src/{alloc => }/btree/set/tests.rs (99%) rename crates/rune-alloc/src/{alloc => }/btree/set_val.rs (88%) rename crates/rune-alloc/src/{alloc => }/btree/split.rs (100%) rename crates/rune-alloc/src/{alloc/try_clone.rs => clone.rs} (75%) create mode 100644 crates/rune-alloc/src/error.rs rename crates/rune-alloc/src/{alloc => }/hashbrown/map.rs (99%) rename crates/rune-alloc/src/{alloc => }/hashbrown/mod.rs (96%) rename crates/rune-alloc/src/{alloc => }/hashbrown/raw/bitmask.rs (100%) rename crates/rune-alloc/src/{alloc => }/hashbrown/raw/generic.rs (100%) rename crates/rune-alloc/src/{alloc => }/hashbrown/raw/mod.rs (99%) rename crates/rune-alloc/src/{alloc => }/hashbrown/raw/neon.rs (100%) rename crates/rune-alloc/src/{alloc => }/hashbrown/raw/sse2.rs (100%) rename crates/rune-alloc/src/{alloc => }/hashbrown/scopeguard.rs (100%) create mode 100644 crates/rune-alloc/src/hashbrown/serde.rs rename crates/rune-alloc/src/{alloc => }/hashbrown/set.rs (99%) create mode 100644 crates/rune-alloc/src/iter/join.rs create mode 100644 crates/rune-alloc/src/iter/try_cloned.rs rename crates/rune-alloc/src/{alloc => iter}/try_extend.rs (96%) rename crates/rune-alloc/src/{alloc => iter}/try_from_iterator.rs (97%) create mode 100644 crates/rune-alloc/src/limit.rs create mode 100644 crates/rune-alloc/src/limit/no_std.rs create mode 100644 crates/rune-alloc/src/limit/std.rs create mode 100644 crates/rune-alloc/src/no_std.rs create mode 100644 crates/rune-alloc/src/option/ext.rs create mode 100644 crates/rune-alloc/src/option/mod.rs rename crates/{rune/src/no_std => rune-alloc/src}/path.rs (66%) rename crates/rune-alloc/src/{alloc => }/raw_vec.rs (99%) create mode 100644 crates/rune-alloc/src/serde/de.rs create mode 100644 crates/rune-alloc/src/serde/mod.rs create mode 100644 crates/rune-alloc/src/serde/ser.rs rename crates/rune-alloc/src/{alloc => }/str.rs (86%) rename crates/rune-alloc/src/{alloc/string.rs => string/mod.rs} (89%) rename crates/rune-alloc/src/{alloc => }/string/serde.rs (83%) rename crates/rune-alloc/src/{alloc => }/string/try_to_string.rs (88%) rename crates/rune-alloc/src/{alloc => }/vec/drain.rs (99%) rename crates/rune-alloc/src/{alloc => }/vec/into_iter.rs (98%) rename crates/rune-alloc/src/{alloc => }/vec/is_zero.rs (100%) rename crates/rune-alloc/src/{alloc => }/vec/mod.rs (97%) rename crates/rune-alloc/src/{alloc => }/vec/partial_eq.rs (95%) rename crates/rune-alloc/src/{alloc => }/vec/set_len_on_drop.rs (100%) rename crates/rune-alloc/src/{alloc => }/vec/spec_extend.rs (94%) rename crates/rune-alloc/src/{alloc => }/vec/spec_from_elem.rs (95%) rename crates/rune-alloc/src/{alloc => }/vec/splice.rs (98%) rename crates/rune-alloc/src/{alloc => }/vec_deque/drain.rs (100%) rename crates/rune-alloc/src/{alloc => }/vec_deque/into_iter.rs (97%) rename crates/rune-alloc/src/{alloc => }/vec_deque/iter.rs (100%) rename crates/rune-alloc/src/{alloc => }/vec_deque/iter_mut.rs (100%) rename crates/rune-alloc/src/{alloc => }/vec_deque/macros.rs (100%) rename crates/rune-alloc/src/{alloc => }/vec_deque/mod.rs (98%) rename crates/rune-alloc/src/{alloc => }/vec_deque/raw_iter.rs (100%) create mode 100644 crates/rune-core/src/item/serde.rs delete mode 100644 crates/rune/src/no_std/anyhow.rs create mode 100644 crates/rune/src/support.rs create mode 100644 no-std-examples/.gitignore create mode 100644 no-std-examples/Cargo.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a71003ecb..3ec1b2675 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: with: components: clippy - uses: Swatinem/rust-cache@v2 - - run: cargo clippy --workspace --exclude no-std-examples --exclude generate --all-features --all-targets -- -D warnings + - run: cargo clippy --workspace --exclude generate --all-features --all-targets -- -D warnings docs: runs-on: ubuntu-latest @@ -99,7 +99,7 @@ jobs: strategy: fail-fast: false matrix: - feature: [capture-io, doc, fmt, cli, workspace, byte-code] + feature: [capture-io, "cli,doc", "cli,fmt", cli, workspace, byte-code] steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable @@ -117,15 +117,24 @@ jobs: - uses: Swatinem/rust-cache@v2 - run: cargo build -p rune-wasm --target wasm32-unknown-unknown + no_std_minimal: + runs-on: windows-latest + needs: basics + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - uses: Swatinem/rust-cache@v2 + - run: cargo run --manifest-path=no-std-examples/Cargo.toml --profile unix --example no_std_minimal + test: runs-on: ubuntu-latest - needs: [no_default_features, build_feature, docs, msrv, miri_rune, miri_rune_alloc, wasm] + needs: [no_default_features, build_feature, docs, msrv, miri_rune, miri_rune_alloc, no_std_minimal, wasm] steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: cargo build -p rune --no-default-features --features alloc - - run: cargo test --workspace --exclude no-std-examples --all-targets - - run: cargo test --workspace --exclude no-std-examples --doc + - run: cargo test --workspace --all-targets + - run: cargo test --workspace --doc - run: cargo run --bin rune -- check --recursive --experimental scripts - run: cargo run --bin rune -- test --recursive --experimental scripts --opt include-std diff --git a/Cargo.toml b/Cargo.toml index 3095048ad..a85de7b7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,13 @@ [workspace] resolver = "2" + members = [ "crates/*", "examples", "benches", "tools/*", - "no-std-examples", ] + default-members = [ "crates/*", "examples", @@ -14,6 +15,7 @@ default-members = [ "tools/site", "tools/builder", ] +exclude = ["no-std-examples"] [profile.bench] lto = false diff --git a/README.md b/README.md index 7df625879..217270553 100644 --- a/README.md +++ b/README.md @@ -80,9 +80,9 @@ use rune::termcolor::{ColorChoice, StandardStream}; use std::sync::Arc; #[tokio::main] -async fn main() -> rune::Result<()> { +async fn main() -> rune::support::Result<()> { let context = Context::with_default_modules()?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = Sources::new(); sources.insert(Source::new( diff --git a/UPGRADING.md b/UPGRADING.md index 218c39024..5b95747a8 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -164,7 +164,7 @@ Must now instead do this: pub(crate) fn stringy_math( cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream, -) -> rune::Result { +) -> rune::support::Result { let mut parser = Parser::from_token_stream(stream, cx.stream_span()); let mut output = quote!(0); @@ -199,4 +199,4 @@ pub(crate) fn stringy_math( [MacroContext]: https://docs.rs/rune/0.10.0/rune/macros/struct.MacroContext.html [rune::macros::eval]: https://docs.rs/rune/0.9.1/rune/macros/fn.eval.html [rune::macros::resolve]: https://docs.rs/rune/0.9.1/rune/macros/fn.resolve.html -[rune::macros::stringify]: https://docs.rs/rune/0.9.1/rune/macros/fn.stringify.html \ No newline at end of file +[rune::macros::stringify]: https://docs.rs/rune/0.9.1/rune/macros/fn.stringify.html diff --git a/benches/benches/bench_main.rs b/benches/benches/bench_main.rs index 8f0a4f427..6161a06bd 100644 --- a/benches/benches/bench_main.rs +++ b/benches/benches/bench_main.rs @@ -11,13 +11,15 @@ pub(crate) fn vm( .with_diagnostics(diagnostics) .build()?; - let context = Arc::new(context.runtime()); + let context = Arc::new(context.runtime()?); Ok(Vm::new(context, Arc::new(unit))) } pub(crate) fn sources(source: &str) -> Sources { let mut sources = Sources::new(); - sources.insert(Source::new("main", source)); + sources + .insert(Source::new("main", source)) + .expect("Failed to insert source"); sources } diff --git a/benches/benches/benchmarks/aoc_2020_19b.rs b/benches/benches/benchmarks/aoc_2020_19b.rs index c6aa6e91c..6ef4b6b5f 100644 --- a/benches/benches/benchmarks/aoc_2020_19b.rs +++ b/benches/benches/benchmarks/aoc_2020_19b.rs @@ -1,6 +1,6 @@ use criterion::Criterion; -use rune::alloc::TryClone; +use rune::alloc::prelude::*; criterion::criterion_group!(benches, aoc_2020_19b); diff --git a/benches/benches/benchmarks/aoc_2020_1a.rs b/benches/benches/benchmarks/aoc_2020_1a.rs index 967ab7f84..627a1694f 100644 --- a/benches/benches/benchmarks/aoc_2020_1a.rs +++ b/benches/benches/benchmarks/aoc_2020_1a.rs @@ -4,7 +4,7 @@ use anyhow::Context; use criterion::Criterion; -use rune::alloc::TryClone; +use rune::alloc::prelude::*; criterion::criterion_group!(benches, aoc_2020_1a); diff --git a/benches/benches/benchmarks/aoc_2020_1b.rs b/benches/benches/benchmarks/aoc_2020_1b.rs index a5b0ead68..6be98941f 100644 --- a/benches/benches/benchmarks/aoc_2020_1b.rs +++ b/benches/benches/benchmarks/aoc_2020_1b.rs @@ -4,7 +4,7 @@ use criterion::Criterion; -use rune::alloc::TryClone; +use rune::alloc::prelude::*; criterion::criterion_group!(benches, aoc_2020_1b); diff --git a/benches/benches/benchmarks/brainfuck.rs b/benches/benches/benchmarks/brainfuck.rs index 7f62526e3..e484220e4 100644 --- a/benches/benches/benchmarks/brainfuck.rs +++ b/benches/benches/benchmarks/brainfuck.rs @@ -1,5 +1,6 @@ use criterion::Criterion; -use rune::{Hash, Result, Vm}; +use rune::support::Result; +use rune::{Hash, Vm}; use rune::modules::capture_io::CaptureIo; diff --git a/crates/rune-alloc-macros/Cargo.toml b/crates/rune-alloc-macros/Cargo.toml new file mode 100644 index 000000000..3b7fd8da2 --- /dev/null +++ b/crates/rune-alloc-macros/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rune-alloc-macros" +version = "0.12.3" +authors = ["John-John Tedro "] +edition = "2021" +rust-version = "1.70" +description = "Macros for the Rune Language, an embeddable dynamic programming language for Rust." +documentation = "https://docs.rs/rune" +readme = "README.md" +homepage = "https://github.com/rune-rs/rune" +repository = "https://github.com/rune-rs/rune" +license = "MIT OR Apache-2.0" +keywords = ["language", "scripting", "scripting-language"] +categories = ["parser-implementations"] + +[dependencies] +syn = { version = "2.0.16", features = ["full"] } +quote = "1.0.27" +proc-macro2 = "1.0.56" + +[lib] +proc-macro = true diff --git a/crates/rune-alloc-macros/src/context.rs b/crates/rune-alloc-macros/src/context.rs new file mode 100644 index 000000000..609178fe2 --- /dev/null +++ b/crates/rune-alloc-macros/src/context.rs @@ -0,0 +1,68 @@ +use std::cell::RefCell; + +use proc_macro2::Span; +use syn::spanned::Spanned as _; + +#[derive(Default)] +pub(crate) struct Context { + pub(crate) errors: RefCell>, + pub(crate) module: Option, +} + +impl Context { + /// Construct a new context. + pub(crate) fn new() -> Self { + Self::default() + } + + /// Register an error. + pub(crate) fn error(&self, error: syn::Error) { + self.errors.borrow_mut().push(error) + } + + /// Test if context has any errors. + pub(crate) fn has_errors(&self) -> bool { + !self.errors.borrow().is_empty() + } + + /// Convert into errors. + pub(crate) fn into_errors(self) -> Vec { + self.errors.into_inner() + } + + pub(crate) fn tokens_with_module(&self, module: Option<&syn::Path>) -> Tokens { + let default_module; + + let m = match module { + Some(module) => module, + None => match &self.module { + Some(module) => module, + None => { + default_module = syn::Path::from(syn::Ident::new("rune", Span::call_site())); + &default_module + } + }, + }; + + Tokens { + try_clone: path(m, ["alloc", "clone", "TryClone"]), + alloc: path(m, ["alloc"]), + } + } +} + +fn path(base: &syn::Path, path: [&'static str; N]) -> syn::Path { + let mut base = base.clone(); + + for s in path { + let ident = syn::Ident::new(s, base.span()); + base.segments.push(syn::PathSegment::from(ident)); + } + + base +} + +pub(crate) struct Tokens { + pub(crate) try_clone: syn::Path, + pub(crate) alloc: syn::Path, +} diff --git a/crates/rune-alloc-macros/src/lib.rs b/crates/rune-alloc-macros/src/lib.rs new file mode 100644 index 000000000..cf4ac26e6 --- /dev/null +++ b/crates/rune-alloc-macros/src/lib.rs @@ -0,0 +1,47 @@ +//! rune logo +//!
+//! github +//! crates.io +//! docs.rs +//! chat on discord +//!
+//! Minimum support: Rust 1.70+. +//!
+//!
+//! Visit the site 🌐 +//! — +//! Read the book 📖 +//!
+//!
+//! +//! Macros for the Rune Language, an embeddable dynamic programming language for Rust. +//! +//!
+//! +//! ## Usage +//! +//! This is part of the [Rune Language](https://rune-rs.github.io). + +#![allow(clippy::manual_map)] + +extern crate proc_macro; + +mod context; +mod try_clone; + +#[proc_macro_derive(TryClone, attributes(try_clone))] +pub fn try_clone(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = syn::parse_macro_input!(input as syn::DeriveInput); + + try_clone::expand(input) + .unwrap_or_else(to_compile_errors) + .into() +} + +fn to_compile_errors(errors: I) -> proc_macro2::TokenStream +where + I: IntoIterator, +{ + let compile_errors = errors.into_iter().map(syn::Error::into_compile_error); + ::quote::quote!(#(#compile_errors)*) +} diff --git a/crates/rune-alloc-macros/src/try_clone.rs b/crates/rune-alloc-macros/src/try_clone.rs new file mode 100644 index 000000000..13b5430fb --- /dev/null +++ b/crates/rune-alloc-macros/src/try_clone.rs @@ -0,0 +1,255 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::parse::Parse; + +use crate::context::{Context, Tokens}; + +pub(super) fn expand(mut input: syn::DeriveInput) -> Result> { + let cx = Context::new(); + let tokens = cx.tokens_with_module(None); + + let attr = parse_type_attr(&cx, &input.attrs); + + if !attr.predicates.is_empty() { + input + .generics + .make_where_clause() + .predicates + .extend(attr.predicates); + } + + let Tokens { + try_clone, alloc, .. + } = &tokens; + + let implementation = if attr.copy { + quote!(*self) + } else { + match input.data { + syn::Data::Struct(st) => { + let fields = st.fields.into_iter().enumerate().map(|(index, f)| { + let member = match &f.ident { + Some(ident) => syn::Member::Named(ident.clone()), + None => syn::Member::Unnamed(syn::Index::from(index)), + }; + + let attr = parse_field_attr(&cx, &f.attrs); + + let expr = match attr.with { + With::Copy => quote! { self.#member }, + With::None => quote! { #try_clone::try_clone(&self.#member)? }, + With::With(with) => quote! { #with(&self.#member) }, + With::TryWith(with) => quote! { #with(&self.#member)? }, + }; + + syn::FieldValue { + attrs: Vec::new(), + member, + colon_token: Some(::default()), + expr: syn::Expr::Verbatim(expr), + } + }); + + quote! { + Self { #(#fields),* } + } + } + syn::Data::Enum(en) => { + let variants = en.variants.into_iter().map(|v| { + let name = v.ident; + + let members = v.fields.iter().enumerate().map(|(index, f)| { + let (member, var) = match &f.ident { + Some(ident) => ( + syn::Member::Named(ident.clone()), + quote::format_ident!("{}", ident), + ), + None => ( + syn::Member::Unnamed(syn::Index::from(index)), + quote::format_ident!("_{}", index), + ), + }; + + let attr = parse_field_attr(&cx, &f.attrs); + (index, f, member, var, attr) + }); + + let assigns = + members + .clone() + .map(|(index, f, member, var, _)| match &f.ident { + Some(..) => syn::FieldValue { + attrs: Vec::new(), + member, + colon_token: None, + expr: syn::Expr::Verbatim(quote!()), + }, + None => { + let member = syn::Member::Unnamed(syn::Index::from(index)); + + let expr = syn::Expr::Path(syn::ExprPath { + attrs: Vec::new(), + qself: None, + path: syn::Path::from(var), + }); + + syn::FieldValue { + attrs: Vec::new(), + member, + colon_token: Some(::default()), + expr, + } + } + }); + + let fields = members.clone().map(|(_, _, member, var, attr)| { + let expr = match attr.with { + With::Copy => quote! { *#var }, + With::None => quote! { #try_clone::try_clone(#var)? }, + With::With(with) => quote! { #with(#var) }, + With::TryWith(with) => quote! { #with(#var)? }, + }; + + syn::FieldValue { + attrs: Vec::new(), + member, + colon_token: Some(::default()), + expr: syn::Expr::Verbatim(expr), + } + }); + + quote! { + Self::#name { #(#assigns),* } => { + Self::#name { #(#fields),* } + } + } + }); + + quote! { + match self { + #(#variants),* + } + } + } + syn::Data::Union(un) => { + cx.error(syn::Error::new_spanned( + un.union_token, + "TryClone: Unions are not supported", + )); + quote!() + } + } + }; + + if cx.has_errors() { + return Err(cx.into_errors()); + } + + let name = input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + Ok(quote! { + impl #impl_generics #try_clone for #name #ty_generics #where_clause { + fn try_clone(&self) -> #alloc::Result { + Ok(#implementation) + } + } + }) +} + +#[derive(Default)] +struct TypeAttr { + predicates: syn::punctuated::Punctuated, + copy: bool, +} + +fn parse_type_attr(cx: &Context, input: &[syn::Attribute]) -> TypeAttr { + let mut attr = TypeAttr::default(); + + for a in input { + if !a.path().is_ident("try_clone") { + continue; + } + + let result = a.parse_nested_meta(|parser| { + if parser.path.is_ident("bound") { + parser.input.parse::()?; + let content; + syn::braced!(content in parser.input); + attr.predicates + .extend(content.parse_terminated(syn::WherePredicate::parse, syn::Token![,])?); + return Ok(()); + } + + if parser.path.is_ident("copy") { + attr.copy = true; + return Ok(()); + } + + Err(syn::Error::new( + parser.input.span(), + "unsupported attribute", + )) + }); + + if let Err(error) = result { + cx.error(error); + } + } + + attr +} + +#[derive(Default, Clone)] +enum With { + #[default] + None, + Copy, + With(syn::Path), + TryWith(syn::Path), +} + +#[derive(Default, Clone)] +struct FieldAttr { + with: With, +} + +fn parse_field_attr(cx: &Context, input: &[syn::Attribute]) -> FieldAttr { + let mut attr = FieldAttr::default(); + + for a in input { + if !a.path().is_ident("try_clone") { + continue; + } + + let result = a.parse_nested_meta(|parser| { + if parser.path.is_ident("with") { + parser.input.parse::()?; + attr.with = With::With(parser.input.parse()?); + return Ok(()); + } + + if parser.path.is_ident("try_with") { + parser.input.parse::()?; + attr.with = With::TryWith(parser.input.parse()?); + return Ok(()); + } + + if parser.path.is_ident("copy") { + attr.with = With::Copy; + return Ok(()); + } + + Err(syn::Error::new( + parser.input.span(), + "unsupported attribute", + )) + }); + + if let Err(error) = result { + cx.error(error); + } + } + + attr +} diff --git a/crates/rune-alloc/Cargo.toml b/crates/rune-alloc/Cargo.toml index a73cd184b..baea80160 100644 --- a/crates/rune-alloc/Cargo.toml +++ b/crates/rune-alloc/Cargo.toml @@ -15,12 +15,15 @@ categories = ["parser-implementations"] [features] default = ["std", "serde"] -std = ["alloc", "ahash/std"] +std = ["alloc", "ahash/std", "serde?/std"] alloc = [] [dependencies] -serde = { version = "1.0", optional = true } +rune-alloc-macros = { version = "=0.12.3", path = "../rune-alloc-macros" } + +serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } ahash = { version = "0.8.3", default-features = false } +pin-project = "1.1.0" [dev-dependencies] rand = { version = "0.8.5", features = ["small_rng"] } diff --git a/crates/rune-alloc/src/alloc/allocator.rs b/crates/rune-alloc/src/alloc/allocator.rs index c215e45c8..6a14951bd 100644 --- a/crates/rune-alloc/src/alloc/allocator.rs +++ b/crates/rune-alloc/src/alloc/allocator.rs @@ -1,30 +1,9 @@ //! Types used to govern how allocations are performed. use core::alloc::Layout; -use core::fmt; -use crate::ptr::{self, invalid_mut, NonNull}; - -use ::rust_alloc::alloc::{alloc, alloc_zeroed, dealloc}; - -/// Error raised while allocating. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct AllocError { - pub(crate) layout: Layout, -} - -impl fmt::Display for AllocError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Failed to allocate {} bytes of memory", - self.layout.size() - ) - } -} - -#[cfg(feature = "std")] -impl ::rust_std::error::Error for AllocError {} +use crate::alloc::AllocError; +use crate::ptr::{self, NonNull}; /// An implementation of `Allocator` can allocate, grow, shrink, and deallocate /// arbitrary blocks of data described via [`Layout`]. @@ -299,8 +278,7 @@ where #[inline] unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).deallocate(ptr, layout) } + (**self).deallocate(ptr, layout) } #[inline] @@ -310,8 +288,7 @@ where old_layout: Layout, new_layout: Layout, ) -> Result, AllocError> { - // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).grow(ptr, old_layout, new_layout) } + (**self).grow(ptr, old_layout, new_layout) } #[inline] @@ -321,63 +298,6 @@ where old_layout: Layout, new_layout: Layout, ) -> Result, AllocError> { - // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).shrink(ptr, old_layout, new_layout) } - } -} - -/// The default global allocator. -#[derive(Default, Debug, Clone)] -pub struct Global; - -impl Global { - #[inline] - fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { - /// Creates a `NonNull` that is dangling, but well-aligned for this Layout. - /// - /// Note that the pointer value may potentially represent a valid pointer, which - /// means this must not be used as a "not yet initialized" sentinel value. Types - /// that lazily allocate must track initialization by some other means. - pub(crate) const fn dangling(layout: &Layout) -> NonNull { - unsafe { NonNull::new_unchecked(invalid_mut::(layout.align())) } - } - - match layout.size() { - 0 => Ok(NonNull::slice_from_raw_parts(dangling(&layout), 0)), - // SAFETY: `layout` is non-zero in size, - size => unsafe { - let raw_ptr = if zeroed { - alloc_zeroed(layout) - } else { - alloc(layout) - }; - - let Some(ptr) = NonNull::new(raw_ptr) else { - return Err(AllocError { layout }); - }; - - Ok(NonNull::slice_from_raw_parts(ptr, size)) - }, - } - } -} - -unsafe impl Allocator for Global { - #[inline] - fn allocate(&self, layout: Layout) -> Result, AllocError> { - self.alloc_impl(layout, false) - } - - #[inline] - fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { - self.alloc_impl(layout, true) - } - - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - if layout.size() != 0 { - // SAFETY: `layout` is non-zero in size, - // other conditions must be upheld by the caller - unsafe { dealloc(ptr.as_ptr(), layout) } - } + (**self).shrink(ptr, old_layout, new_layout) } } diff --git a/crates/rune-alloc/src/alloc/borrow/mod.rs b/crates/rune-alloc/src/alloc/borrow/mod.rs deleted file mode 100644 index 877b3cfb8..000000000 --- a/crates/rune-alloc/src/alloc/borrow/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub use self::try_to_owned::TryToOwned; -pub(crate) mod try_to_owned; diff --git a/crates/rune-alloc/src/alloc/borrow/try_to_owned.rs b/crates/rune-alloc/src/alloc/borrow/try_to_owned.rs deleted file mode 100644 index c77729e83..000000000 --- a/crates/rune-alloc/src/alloc/borrow/try_to_owned.rs +++ /dev/null @@ -1,43 +0,0 @@ -use core::borrow::Borrow; - -use crate::{Error, TryClone}; - -/// A generalization of `TryClone` to borrowed data. -/// -/// Some types make it possible to go from borrowed to owned, usually by -/// implementing the `TryClone` trait. But `TryClone` works only for going from -/// `&T` to `T`. The `ToOwned` trait generalizes `TryClone` to construct owned -/// data from any borrow of a given type. -pub trait TryToOwned { - /// The resulting type after obtaining ownership. - type Owned: Borrow; - - /// Creates owned data from borrowed data, usually by cloning. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use rune_alloc::{Vec, String, TryToOwned}; - /// - /// let s: &str = "a"; - /// let ss: String = s.try_to_owned()?; - /// # let v: &[i32] = &[1, 2]; - /// # let vv: Vec = v.try_to_owned()?; - /// # Ok::<_, rune_alloc::Error>(()) - /// ``` - fn try_to_owned(&self) -> Result; -} - -impl TryToOwned for T -where - T: TryClone, -{ - type Owned = T; - - #[inline] - fn try_to_owned(&self) -> Result { - self.try_clone() - } -} diff --git a/crates/rune-alloc/src/alloc/global.rs b/crates/rune-alloc/src/alloc/global.rs new file mode 100644 index 000000000..a06a56925 --- /dev/null +++ b/crates/rune-alloc/src/alloc/global.rs @@ -0,0 +1,85 @@ +use core::alloc::Layout; + +use crate::alloc::{AllocError, Allocator}; +use crate::ptr::{invalid_mut, NonNull}; + +#[cfg(feature = "alloc")] +use ::rust_alloc::alloc::{alloc, alloc_zeroed, dealloc}; + +/// Creates a `NonNull` that is dangling, but well-aligned for this Layout. +/// +/// Note that the pointer value may potentially represent a valid pointer, which +/// means this must not be used as a "not yet initialized" sentinel value. Types +/// that lazily allocate must track initialization by some other means. +pub(crate) const fn dangling(layout: &Layout) -> NonNull { + unsafe { NonNull::new_unchecked(invalid_mut::(layout.align())) } +} + +/// The default global allocator for Rune. +/// +/// This supports enforcing thread-local memory limits through the [`limit`] +/// module. +/// +/// [`limit`]: crate::limit +#[derive(Default, Debug, Clone, Copy)] +pub struct Global; + +impl Global { + /// Release the specified memory from being accounted for. + pub(crate) fn release(&self, layout: Layout) { + crate::limit::release(layout.size()); + } + + /// Acquire the specified memory. + pub(crate) fn take(&self, layout: Layout) -> Result<(), AllocError> { + if !crate::limit::take(layout.size()) { + return Err(AllocError { layout }); + } + + Ok(()) + } + + #[inline] + fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { + self.take(layout)?; + + match layout.size() { + 0 => Ok(NonNull::slice_from_raw_parts(dangling(&layout), 0)), + // SAFETY: `layout` is non-zero in size, + size => unsafe { + let raw_ptr = if zeroed { + alloc_zeroed(layout) + } else { + alloc(layout) + }; + + let Some(ptr) = NonNull::new(raw_ptr) else { + return Err(AllocError { layout }); + }; + + Ok(NonNull::slice_from_raw_parts(ptr, size)) + }, + } + } +} + +unsafe impl Allocator for Global { + #[inline] + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.alloc_impl(layout, false) + } + + #[inline] + fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { + self.alloc_impl(layout, true) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + if layout.size() != 0 { + // SAFETY: `layout` is non-zero in size, + // other conditions must be upheld by the caller + dealloc(ptr.as_ptr(), layout); + self.release(layout); + } + } +} diff --git a/crates/rune-alloc/src/alloc/mod.rs b/crates/rune-alloc/src/alloc/mod.rs index c52f6e6fb..5e4c57467 100644 --- a/crates/rune-alloc/src/alloc/mod.rs +++ b/crates/rune-alloc/src/alloc/mod.rs @@ -1,116 +1,35 @@ //! Allocated types. -pub(crate) mod raw_vec; +pub use self::allocator::Allocator; +mod allocator; -pub use self::borrow::TryToOwned; -pub(crate) mod borrow; - -pub use self::allocator::{AllocError, Allocator, Global}; -pub(crate) mod allocator; - -pub use self::boxed::Box; -pub mod boxed; - -pub(crate) mod btree; - -pub use self::hashbrown::HashMap; -pub mod hashbrown; - -pub use self::vec::Vec; -pub mod vec; - -pub use self::vec_deque::VecDeque; -pub mod vec_deque; - -pub use self::try_clone::{TryClone, TryCopy}; -mod try_clone; - -pub use self::try_extend::TryExtend; -mod try_extend; - -pub use self::try_from_iterator::{TryFromIterator, TryFromIteratorIn}; -mod try_from_iterator; - -pub use self::string::String; -pub mod string; - -mod slice; -pub mod str; - -#[cfg(test)] -pub(crate) mod testing; +pub use self::global::Global; +mod global; +use core::alloc::Layout; use core::convert::Infallible; use core::fmt; -/// An error type returned when a custom error is available alongside an allocation error. -#[derive(Debug)] -pub enum CustomError { - /// Custom error being returned. - Custom(E), - /// Try reserve error being returned. - Error(Error), -} - -impl From for CustomError { - fn from(error: Error) -> Self { - CustomError::Error(error) - } -} +use crate::error::{CustomError, Error}; -impl From for CustomError { - fn from(error: AllocError) -> Self { - CustomError::Error(Error::from(error)) - } -} - -/// The error type for methods which allocate or reserve. +/// Error raised while allocating. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[non_exhaustive] -pub enum Error { - /// Error due to the computed capacity exceeding the collection's maximum - /// (usually `isize::MAX` bytes). - #[doc(hidden)] - CapacityOverflow, - - /// Error when computing layout. - #[doc(hidden)] - LayoutError, - - /// The memory allocator returned an error - #[doc(hidden)] - AllocError { - /// The layout of the allocation request that failed. - error: AllocError, - }, -} - -impl From for Error { - #[inline] - fn from(error: AllocError) -> Self { - Error::AllocError { error } - } +pub struct AllocError { + pub(crate) layout: Layout, } -impl fmt::Display for Error { +impl fmt::Display for AllocError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::CapacityOverflow => write!(f, "Capacity overflow"), - Error::LayoutError => write!(f, "Layout error"), - Error::AllocError { error } => error.fmt(f), - } + write!( + f, + "Failed to allocate {} bytes of memory", + self.layout.size() + ) } } #[cfg(feature = "std")] -impl ::rust_std::error::Error for Error { - fn source(&self) -> Option<&(dyn ::rust_std::error::Error + 'static)> { - match self { - Error::AllocError { error } => Some(error), - _ => None, - } - } -} +impl ::std::error::Error for AllocError {} pub(crate) trait SizedTypeProperties: Sized { const IS_ZST: bool = core::mem::size_of::() == 0; diff --git a/crates/rune-alloc/src/alloc/slice.rs b/crates/rune-alloc/src/alloc/slice.rs deleted file mode 100644 index ab18e8dd2..000000000 --- a/crates/rune-alloc/src/alloc/slice.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::alloc::{Allocator, Box, Error, Global, TryClone, TryToOwned, Vec}; - -/// Converts `self` into a vector without clones or allocation. -/// -/// The resulting vector can be converted back into a box via -/// `Vec`'s `into_boxed_slice` method. -/// -/// # Examples -/// -/// ``` -/// let s: Box<[i32]> = Box::new([10, 40, 30]); -/// let x = s.into_vec(); -/// // `s` cannot be used anymore because it has been converted into `x`. -/// -/// assert_eq!(x, vec![10, 40, 30]); -/// ``` -#[inline] -pub fn into_vec(this: Box<[T], A>) -> Vec { - // N.B., see the `hack` module in this file for more details. - hack::into_vec(this) -} - -#[inline] -pub(crate) fn to_vec(s: &[T], alloc: A) -> Result, Error> -where - T: TryClone, -{ - hack::to_vec(s, alloc) -} - -impl TryToOwned for [T] -where - T: TryClone, -{ - type Owned = Vec; - - #[inline] - fn try_to_owned(&self) -> Result { - hack::to_vec(self, Global) - } -} - -// HACK(japaric): With cfg(test) `impl [T]` is not available, these three -// functions are actually methods that are in `impl [T]` but not in -// `core::slice::SliceExt` - we need to supply these functions for the -// `test_permutations` test -pub(crate) mod hack { - use crate::alloc::{Allocator, Box, Error, TryClone, Vec}; - - // We shouldn't add inline attribute to this since this is used in `vec!` - // macro mostly and causes perf regression. See #71204 for discussion and - // perf results. - pub(crate) fn into_vec(b: Box<[T], A>) -> Vec { - unsafe { - let len = b.len(); - let (b, alloc) = Box::into_raw_with_allocator(b); - Vec::from_raw_parts_in(b as *mut T, len, len, alloc) - } - } - - #[inline] - pub(crate) fn to_vec( - s: &[T], - alloc: A, - ) -> Result, Error> { - T::to_vec(s, alloc) - } - - pub(crate) trait ConvertVec { - fn to_vec(s: &[Self], alloc: A) -> Result, Error> - where - Self: Sized; - } - - impl ConvertVec for T - where - T: TryClone, - { - #[inline] - fn to_vec(s: &[Self], alloc: A) -> Result, Error> { - struct DropGuard<'a, T, A: Allocator> { - vec: &'a mut Vec, - num_init: usize, - } - impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { - #[inline] - fn drop(&mut self) { - // SAFETY: - // items were marked initialized in the loop below - unsafe { - self.vec.set_len(self.num_init); - } - } - } - let mut vec = Vec::try_with_capacity_in(s.len(), alloc)?; - let mut guard = DropGuard { - vec: &mut vec, - num_init: 0, - }; - let slots = guard.vec.spare_capacity_mut(); - // .take(slots.len()) is necessary for LLVM to remove bounds checks - // and has better codegen than zip. - for (i, b) in s.iter().enumerate().take(slots.len()) { - guard.num_init = i; - slots[i].write(b.try_clone()?); - } - core::mem::forget(guard); - // SAFETY: - // the vec was allocated and initialized above to at least this length. - unsafe { - vec.set_len(s.len()); - } - Ok(vec) - } - } - - #[cfg(rune_nightly)] - impl ConvertVec for T { - #[inline] - fn to_vec(s: &[Self], alloc: A) -> Result, Error> { - let mut v = Vec::try_with_capacity_in(s.len(), alloc)?; - - // SAFETY: - // allocated above with the capacity of `s`, and initialize to `s.len()` in - // ptr::copy_to_non_overlapping below. - unsafe { - s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); - v.set_len(s.len()); - } - Ok(v) - } - } -} diff --git a/crates/rune-alloc/src/alloc/testing.rs b/crates/rune-alloc/src/alloc/testing.rs deleted file mode 100644 index 21da59a75..000000000 --- a/crates/rune-alloc/src/alloc/testing.rs +++ /dev/null @@ -1,75 +0,0 @@ -use core::convert::Infallible; -use core::fmt; - -use super::{AllocError, CustomError, Error}; - -pub(crate) trait CustomTestExt { - fn custom_result(self) -> Result; -} - -impl CustomTestExt for Result> { - fn custom_result(self) -> Result { - match self { - Ok(value) => Ok(value), - Err(CustomError::Custom(error)) => Err(error), - Err(CustomError::Error(error)) => handle_error(error), - } - } -} - -pub(crate) trait TestExt { - fn abort(self) -> T; -} - -impl TestExt for Result { - fn abort(self) -> T { - match self { - Ok(value) => value, - Err(error) => match error {}, - } - } -} - -impl TestExt for Result { - fn abort(self) -> T { - match self { - Ok(value) => value, - Err(error) => handle_error(error), - } - } -} - -impl TestExt for Result { - fn abort(self) -> T { - match self { - Ok(value) => value, - Err(error) => ::rust_alloc::alloc::handle_alloc_error(error.layout), - } - } -} - -impl TestExt for Result> -where - E: fmt::Display, -{ - fn abort(self) -> T { - match self { - Ok(value) => value, - Err(error) => match error { - CustomError::Custom(error) => { - panic!("{}", error) - } - CustomError::Error(error) => handle_error(error), - }, - } - } -} - -fn handle_error(error: Error) -> ! { - match error { - Error::AllocError { error } => ::rust_alloc::alloc::handle_alloc_error(error.layout), - error => { - panic!("{}", error) - } - } -} diff --git a/crates/rune-alloc/src/borrow/mod.rs b/crates/rune-alloc/src/borrow/mod.rs new file mode 100644 index 000000000..e52ca464d --- /dev/null +++ b/crates/rune-alloc/src/borrow/mod.rs @@ -0,0 +1,406 @@ +use core::borrow::Borrow; +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::ops::Deref; + +#[cfg(feature = "alloc")] +use ::rust_alloc::borrow::ToOwned; + +use crate::clone::TryClone; +use crate::error::Error; +use crate::vec::Vec; + +/// A generalization of `TryClone` to borrowed data. +/// +/// Some types make it possible to go from borrowed to owned, usually by +/// implementing the `TryClone` trait. But `TryClone` works only for going from +/// `&T` to `T`. The `ToOwned` trait generalizes `TryClone` to construct owned +/// data from any borrow of a given type. +pub trait TryToOwned { + /// The resulting type after obtaining ownership. + type Owned: Borrow; + + /// Creates owned data from borrowed data, usually by cloning. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use rune_alloc::{Vec, String}; + /// use rune_alloc::prelude::*; + /// + /// let s: &str = "a"; + /// let ss: String = s.try_to_owned()?; + /// # let v: &[i32] = &[1, 2]; + /// # let vv: Vec = v.try_to_owned()?; + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + fn try_to_owned(&self) -> Result; +} + +impl TryToOwned for T +where + T: TryClone, +{ + type Owned = T; + + #[inline] + fn try_to_owned(&self) -> Result { + self.try_clone() + } +} + +impl TryToOwned for crate::path::Path { + type Owned = crate::path::PathBuf; + + fn try_to_owned(&self) -> Result { + Ok(self.to_path_buf()) + } +} + +/// A clone-on-write smart pointer. +/// +/// The type `Cow` is a smart pointer providing clone-on-write functionality: it +/// can enclose and provide immutable access to borrowed data, and clone the +/// data lazily when mutation or ownership is required. The type is designed to +/// work with general borrowed data via the `Borrow` trait. +/// +/// `Cow` implements `Deref`, which means that you can call non-mutating methods +/// directly on the data it encloses. If mutation is desired, `to_mut` will +/// obtain a mutable reference to an owned value, cloning if necessary. +/// +/// If you need reference-counting pointers, note that +/// [`Rc::make_mut`][rust_alloc::rc::Rc::make_mut] and +/// [`Arc::make_mut`][rust_alloc::sync::Arc::make_mut] can provide +/// clone-on-write functionality as well. +/// +/// # Examples +/// +/// ``` +/// use rune_alloc::borrow::Cow; +/// use rune_alloc::prelude::*; +/// use rune_alloc::try_vec; +/// +/// fn abs_all(input: &mut Cow<'_, [i32]>) -> rune_alloc::Result<()> { +/// for i in 0..input.len() { +/// let v = input[i]; +/// if v < 0 { +/// // Clones into a vector if not already owned. +/// input.try_to_mut()?[i] = -v; +/// } +/// } +/// +/// Ok(()) +/// } +/// +/// // No clone occurs because `input` doesn't need to be mutated. +/// let slice = [0, 1, 2]; +/// let mut input = Cow::from(&slice[..]); +/// abs_all(&mut input)?; +/// +/// // Clone occurs because `input` needs to be mutated. +/// let slice = [-1, 0, 1]; +/// let mut input = Cow::from(&slice[..]); +/// abs_all(&mut input)?; +/// +/// // No clone occurs because `input` is already owned. +/// let mut input = Cow::from(try_vec![-1, 0, 1]); +/// abs_all(&mut input)?; +/// # Ok::<_, rune_alloc::Error>(()) +/// ``` +/// +/// Another example showing how to keep `Cow` in a struct: +/// +/// ``` +/// use rune_alloc::Vec; +/// use rune_alloc::borrow::Cow; +/// use rune_alloc::prelude::*; +/// +/// struct Items<'a, X> where [X]: TryToOwned> { +/// values: Cow<'a, [X]>, +/// } +/// +/// impl<'a, X: TryClone + 'a> Items<'a, X> where [X]: TryToOwned> { +/// fn new(v: Cow<'a, [X]>) -> Self { +/// Items { values: v } +/// } +/// } +/// +/// // Creates a container from borrowed values of a slice +/// let readonly = [1, 2]; +/// let borrowed = Items::new((&readonly[..]).into()); +/// match borrowed { +/// Items { values: Cow::Borrowed(b) } => println!("borrowed {b:?}"), +/// _ => panic!("expect borrowed value"), +/// } +/// +/// let mut clone_on_write = borrowed; +/// // Mutates the data from slice into owned vec and pushes a new value on top +/// clone_on_write.values.try_to_mut()?.try_push(3)?; +/// println!("clone_on_write = {:?}", clone_on_write.values); +/// +/// // The data was mutated. Let's check it out. +/// match clone_on_write { +/// Items { values: Cow::Owned(_) } => println!("clone_on_write contains owned data"), +/// _ => panic!("expect owned data"), +/// } +/// # Ok::<_, rune_alloc::Error>(()) +/// ``` +pub enum Cow<'b, T: ?Sized + 'b> +where + T: TryToOwned, +{ + /// Borrowed data. + Borrowed(&'b T), + /// Owned data. + Owned(::Owned), +} + +impl Cow<'_, B> { + /// Returns true if the data is borrowed, i.e. if `to_mut` would require + /// additional work. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::borrow::Cow; + /// use rune_alloc::prelude::*; + /// + /// let cow = Cow::Borrowed("moo"); + /// assert!(cow.is_borrowed()); + /// + /// let bull: Cow<'_, str> = Cow::Owned("...moo?".try_to_string()?); + /// assert!(!bull.is_borrowed()); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + pub const fn is_borrowed(&self) -> bool { + matches!(self, Cow::Borrowed(..)) + } + + /// Returns true if the data is owned, i.e. if `to_mut` would be a no-op. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::borrow::Cow; + /// use rune_alloc::prelude::*; + /// + /// let cow: Cow<'_, str> = Cow::Owned("moo".try_to_string()?); + /// assert!(cow.is_owned()); + /// + /// let bull = Cow::Borrowed("...moo?"); + /// assert!(!bull.is_owned()); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + pub const fn is_owned(&self) -> bool { + !self.is_borrowed() + } + + /// Acquires a mutable reference to the owned form of the data. + /// + /// Clones the data if it is not already owned. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::borrow::Cow; + /// use rune_alloc::String; + /// + /// let mut cow = Cow::Borrowed("foo"); + /// cow.try_to_mut()?.make_ascii_uppercase(); + /// + /// assert_eq!(cow, Cow::Owned(String::try_from("FOO")?)); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + pub fn try_to_mut(&mut self) -> Result<&mut ::Owned, Error> { + Ok(match *self { + Cow::Borrowed(borrowed) => { + *self = Cow::Owned(borrowed.try_to_owned()?); + + match *self { + Cow::Borrowed(..) => unreachable!(), + Cow::Owned(ref mut owned) => owned, + } + } + Cow::Owned(ref mut owned) => owned, + }) + } + + /// Extracts the owned data. + /// + /// Clones the data if it is not already owned. + /// + /// # Examples + /// + /// Calling `into_owned` on a `Cow::Borrowed` returns a clone of the borrowed data: + /// + /// ``` + /// use rune_alloc::borrow::Cow; + /// use rune_alloc::String; + /// + /// let s = "Hello world!"; + /// let cow = Cow::Borrowed(s); + /// + /// assert_eq!(cow.try_into_owned()?, String::try_from(s)?); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + /// + /// Calling `into_owned` on a `Cow::Owned` returns the owned data. The data is moved out of the + /// `Cow` without being cloned. + /// + /// ``` + /// use rune_alloc::borrow::Cow; + /// use rune_alloc::String; + /// + /// let s = "Hello world!"; + /// let cow: Cow<'_, str> = Cow::Owned(String::try_from(s)?); + /// + /// assert_eq!(cow.try_into_owned()?, String::try_from(s)?); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + pub fn try_into_owned(self) -> Result<::Owned, Error> { + match self { + Cow::Borrowed(borrowed) => borrowed.try_to_owned(), + Cow::Owned(owned) => Ok(owned), + } + } +} + +impl<'a, T: ?Sized + 'a> From<&'a T> for Cow<'a, T> +where + T: TryToOwned, +{ + /// Construct a `Cow` from a reference. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::borrow::Cow; + /// + /// let s = Cow::from("Hello World"); + /// assert_eq!("Hello World", s); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + #[inline] + fn from(b: &'a T) -> Self { + Cow::Borrowed(b) + } +} + +#[cfg(feature = "alloc")] +impl<'a, T: ?Sized + 'a> TryFrom> for Cow<'a, T> +where + T: ToOwned + TryToOwned, + ::Owned: TryFrom<::Owned>, +{ + type Error = <::Owned as TryFrom<::Owned>>::Error; + + fn try_from(value: rust_alloc::borrow::Cow<'a, T>) -> Result { + Ok(match value { + rust_alloc::borrow::Cow::Borrowed(b) => Cow::Borrowed(b), + rust_alloc::borrow::Cow::Owned(o) => Cow::Owned(::Owned::try_from(o)?), + }) + } +} + +impl Deref for Cow<'_, B> +where + B::Owned: Borrow, +{ + type Target = B; + + fn deref(&self) -> &B { + match *self { + Cow::Borrowed(borrowed) => borrowed, + Cow::Owned(ref owned) => owned.borrow(), + } + } +} + +impl AsRef for Cow<'_, T> { + #[inline] + fn as_ref(&self) -> &T { + self + } +} + +impl fmt::Display for Cow<'_, T> +where + T: fmt::Display + TryToOwned, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl fmt::Debug for Cow<'_, T> +where + T: fmt::Debug + TryToOwned, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +impl TryClone for Cow<'_, str> { + #[inline] + fn try_clone(&self) -> Result { + Ok(match self { + Cow::Borrowed(b) => Cow::Borrowed(b), + Cow::Owned(o) => Cow::Owned(o.try_clone()?), + }) + } +} + +impl From> for Cow<'_, [T]> +where + T: TryClone, +{ + fn from(vec: Vec) -> Self { + Cow::Owned(vec) + } +} + +impl PartialEq for Cow<'_, B> +where + B: PartialEq + TryToOwned, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + (**self).eq(&**other) + } +} + +impl Eq for Cow<'_, B> where B: Eq + TryToOwned {} + +impl PartialOrd for Cow<'_, B> +where + B: PartialOrd + TryToOwned, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + (**self).partial_cmp(&**other) + } +} + +impl Ord for Cow<'_, B> +where + B: Ord + TryToOwned, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + (**self).cmp(&**other) + } +} + +impl Hash for Cow<'_, B> +where + B: Hash + TryToOwned, +{ + #[inline] + fn hash(&self, state: &mut H) { + Hash::hash(&**self, state) + } +} diff --git a/crates/rune-alloc/src/alloc/boxed.rs b/crates/rune-alloc/src/boxed.rs similarity index 71% rename from crates/rune-alloc/src/alloc/boxed.rs rename to crates/rune-alloc/src/boxed.rs index 1d1b55239..dbef09f75 100644 --- a/crates/rune-alloc/src/alloc/boxed.rs +++ b/crates/rune-alloc/src/boxed.rs @@ -1,12 +1,19 @@ use core::alloc::Layout; +use core::borrow::{Borrow, BorrowMut}; +use core::cmp::Ordering; use core::fmt; +use core::hash::{Hash, Hasher}; use core::mem; use core::ops::{Deref, DerefMut}; -use crate::alloc::raw_vec::RawVec; -use crate::alloc::{AllocError, Allocator, Error, Global, TryClone, Vec}; -use crate::ptr; -use crate::ptr::Unique; +use crate::alloc::{AllocError, Allocator, Global}; +use crate::clone::TryClone; +use crate::error::Error; +use crate::iter::TryFromIteratorIn; +use crate::path::Path; +use crate::ptr::{self, Unique}; +use crate::raw_vec::RawVec; +use crate::vec::Vec; #[test] fn ensure_niche_size() { @@ -32,10 +39,10 @@ impl Box { /// ``` /// use rune_alloc::Box; /// - /// let five = Box::new(5)?; - /// # Ok::<_, rune_alloc::AllocError>(()) + /// let five = Box::try_new(5)?; + /// # Ok::<_, rune_alloc::Error>(()) /// ``` - pub fn new(value: T) -> Result { + pub fn try_new(value: T) -> Result { Self::try_new_in(value, Global) } } @@ -49,10 +56,11 @@ impl Box { /// # Examples /// /// ``` - /// use rune_alloc::{Box, Global}; + /// use rune_alloc::Box; + /// use rune_alloc::alloc::Global; /// /// let five = Box::try_new_in(5, Global)?; - /// # Ok::<(), rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` #[inline] pub fn try_new_in(x: T, alloc: A) -> Result { @@ -70,7 +78,8 @@ impl Box { /// # Examples /// /// ``` - /// use rune_alloc::{Box, Global}; + /// use rune_alloc::Box; + /// use rune_alloc::alloc::Global; /// /// let mut five = Box::::try_new_uninit_in(Global)?; /// @@ -82,7 +91,7 @@ impl Box { /// }; /// /// assert_eq!(*five, 5); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn try_new_uninit_in(alloc: A) -> Result, A>, AllocError> where @@ -148,7 +157,7 @@ impl Box { /// # fn main() -> Result<(), rune_alloc::Error> { /// use rune_alloc::Box; /// - /// let x = Box::new(41)?; + /// let x = Box::try_new(41)?; /// let static_ref: &'static mut usize = Box::leak(x); /// *static_ref += 1; /// assert_eq!(*static_ref, 42); @@ -200,19 +209,22 @@ impl Box { /// [`Box::into_raw_with_allocator`]: /// /// ``` - /// use rune_alloc::{Box, Global}; + /// use rune_alloc::Box; + /// use rune_alloc::alloc::Global; /// /// let x = Box::try_new_in(5, Global)?; /// let (ptr, alloc) = Box::into_raw_with_allocator(x); /// let x = unsafe { Box::from_raw_in(ptr, alloc) }; - /// # Ok::<(), rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` /// /// Manually create a `Box` from scratch by using the system allocator: /// /// ``` /// use core::alloc::Layout; - /// use rune_alloc::{Box, Allocator, Global}; + /// + /// use rune_alloc::Box; + /// use rune_alloc::alloc::{Allocator, Global}; /// /// unsafe { /// let ptr = Global.allocate(Layout::new::())?.as_ptr() as *mut i32; @@ -222,7 +234,7 @@ impl Box { /// ptr.write(5); /// let x = Box::from_raw_in(ptr, Global); /// } - /// # Ok::<(), rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` /// /// [memory layout]: self#memory-layout @@ -257,7 +269,8 @@ impl Box { /// for automatic cleanup: /// /// ``` - /// use rune_alloc::{Box, String, Global}; + /// use rune_alloc::{Box, String}; + /// use rune_alloc::alloc::Global; /// /// let x = Box::try_new_in(String::try_from("Hello")?, Global)?; /// let (ptr, alloc) = Box::into_raw_with_allocator(x); @@ -271,7 +284,9 @@ impl Box { /// ``` /// use core::alloc::Layout; /// use core::ptr::{self, NonNull}; - /// use rune_alloc::{Allocator, Box, String, Global}; + /// + /// use rune_alloc::{Box, String}; + /// use rune_alloc::alloc::{Allocator, Global}; /// /// let x = Box::try_new_in(String::try_from("Hello")?, Global)?; /// @@ -312,7 +327,8 @@ impl Box, A> { /// # Examples /// /// ``` - /// use rune_alloc::{Box, Global}; + /// use rune_alloc::Box; + /// use rune_alloc::alloc::Global; /// /// let mut five = Box::::try_new_uninit_in(Global)?; /// @@ -324,7 +340,7 @@ impl Box, A> { /// }; /// /// assert_eq!(*five, 5); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` #[inline] pub unsafe fn assume_init(self) -> Box { @@ -340,7 +356,8 @@ impl Box<[T], A> { /// # Examples /// /// ``` - /// use rune_alloc::{Box, Global}; + /// use rune_alloc::Box; + /// use rune_alloc::alloc::Global; /// /// let mut values = Box::<[u32]>::try_new_uninit_slice_in(3, Global)?; /// @@ -387,7 +404,8 @@ impl Box<[mem::MaybeUninit], A> { /// # Examples /// /// ``` - /// use rune_alloc::{Box, Global}; + /// use rune_alloc::Box; + /// use rune_alloc::alloc::Global; /// /// let mut values = Box::<[u32]>::try_new_uninit_slice_in(3, Global)?; /// @@ -428,11 +446,43 @@ where #[inline] fn try_clone(&self) -> Result { let alloc = self.alloc.clone(); - let vec = crate::alloc::slice::to_vec(self, alloc)?; + let vec = crate::slice::to_vec(self, alloc)?; vec.try_into_boxed_slice() } } +impl TryClone for Box { + #[inline] + fn try_clone(&self) -> Result { + let alloc = self.alloc.clone(); + Box::try_from_string_in(self.as_ref(), alloc) + } +} + +impl Borrow for Box { + fn borrow(&self) -> &T { + self + } +} + +impl BorrowMut for Box { + fn borrow_mut(&mut self) -> &mut T { + self + } +} + +impl AsRef for Box { + fn as_ref(&self) -> &T { + self + } +} + +impl AsMut for Box { + fn as_mut(&mut self) -> &mut T { + self + } +} + impl Deref for Box { type Target = T; @@ -539,6 +589,122 @@ impl TryFrom<[T; N]> for Box<[T]> { } } +impl Box<[u8], A> { + pub(crate) fn try_from_bytes_in(bytes: &[u8], alloc: A) -> Result { + let mut vec = Vec::::try_with_capacity_in(bytes.len(), alloc)?; + + unsafe { + ptr::copy_nonoverlapping(bytes.as_ptr(), vec.as_mut_ptr(), bytes.len()); + vec.set_len(bytes.len()); + vec.try_into_boxed_slice() + } + } +} + +impl Box { + pub(crate) fn try_from_string_in(string: &str, alloc: A) -> Result { + unsafe { + let b = Box::try_from_bytes_in(string.as_bytes(), alloc)?; + let (raw, alloc) = Box::into_raw_with_allocator(b); + Ok(Box::from_raw_in(raw as *mut str, alloc)) + } + } +} + +impl Box { + pub(crate) fn try_from_path_in(path: &Path, alloc: A) -> Result { + unsafe { + const CHECK: () = assert!(mem::size_of::<&Path>() == mem::size_of::<&[u8]>()); + // Replace with path.as_os_str().as_encoded_bytes() once that is + // stable. + let bytes = &*(path as *const _ as *const [u8]); + let b = Box::try_from_bytes_in(bytes, alloc)?; + let (raw, alloc) = Box::into_raw_with_allocator(b); + Ok(Box::from_raw_in(raw as *mut Path, alloc)) + } + } +} + +impl TryClone for Box { + #[inline] + fn try_clone(&self) -> Result { + let alloc = self.alloc.clone(); + Box::try_from_path_in(self.as_ref(), alloc) + } +} + +impl TryFrom<&str> for Box { + type Error = Error; + + /// Converts a `&str` into a `Box`. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::Box; + /// + /// let s: Box = Box::try_from("Hello World")?; + /// assert_eq!(s.as_ref(), "Hello World"); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + #[inline] + fn try_from(values: &str) -> Result { + Box::try_from_string_in(values, Global) + } +} + +impl TryFrom<&[u8]> for Box<[u8]> { + type Error = Error; + + /// Converts a `&[u8]` into a `Box<[u8]>`. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::Box; + /// + /// let s: Box<[u8]> = Box::try_from(&b"Hello World"[..])?; + /// assert_eq!(s.as_ref(), b"Hello World"); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + #[inline] + fn try_from(values: &[u8]) -> Result { + Box::try_from_bytes_in(values, Global) + } +} + +impl TryFrom<&Path> for Box { + type Error = Error; + + /// Converts a `&[u8]` into a `Box<[u8]>`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// use rune_alloc::Box; + /// + /// let path = Path::new("foo/bar"); + /// + /// let s: Box = Box::try_from(path)?; + /// assert_eq!(s.as_ref(), Path::new("foo/bar")); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + #[inline] + fn try_from(path: &Path) -> Result { + Box::try_from_path_in(path, Global) + } +} + +impl TryFromIteratorIn for Box<[T], A> { + fn try_from_iter_in(iter: I, alloc: A) -> Result + where + I: IntoIterator, + { + Vec::::try_from_iter_in(iter, alloc)?.try_into_boxed_slice() + } +} + unsafe fn for_value_raw(t: *const T) -> Layout { // SAFETY: we pass along the prerequisites of these functions to the caller // TODO: Use mem::{size_of_val_raw, align_of_val_raw} when they become @@ -548,3 +714,45 @@ unsafe fn for_value_raw(t: *const T) -> Layout { // SAFETY: see rationale in `new` for why this is using the unsafe variant Layout::from_size_align_unchecked(size, align) } + +impl Hash for Box +where + T: Hash, +{ + #[inline] + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} + +impl PartialEq for Box +where + T: PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + (**self).eq(other) + } +} + +impl Eq for Box where T: Eq {} + +impl PartialOrd for Box +where + T: PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + (**self).partial_cmp(other) + } +} + +impl Ord for Box +where + T: Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + (**self).cmp(other) + } +} diff --git a/crates/rune-alloc/src/alloc/btree/append.rs b/crates/rune-alloc/src/btree/append.rs similarity index 99% rename from crates/rune-alloc/src/alloc/btree/append.rs rename to crates/rune-alloc/src/btree/append.rs index 82de09728..f3b46ae06 100644 --- a/crates/rune-alloc/src/alloc/btree/append.rs +++ b/crates/rune-alloc/src/btree/append.rs @@ -1,12 +1,12 @@ use core::iter::FusedIterator; +use crate::alloc::{AllocError, Allocator}; +#[cfg(test)] +use crate::testing::*; + use super::merge_iter::MergeIterInner; use super::node::{self, Root}; -#[cfg(test)] -use crate::alloc::testing::*; -use crate::alloc::{AllocError, Allocator}; - impl Root { /// Appends all key-value pairs from the union of two ascending iterators, /// incrementing a `length` variable along the way. The latter makes it diff --git a/crates/rune-alloc/src/alloc/btree/borrow.rs b/crates/rune-alloc/src/btree/borrow.rs similarity index 100% rename from crates/rune-alloc/src/alloc/btree/borrow.rs rename to crates/rune-alloc/src/btree/borrow.rs diff --git a/crates/rune-alloc/src/alloc/btree/fix.rs b/crates/rune-alloc/src/btree/fix.rs similarity index 100% rename from crates/rune-alloc/src/alloc/btree/fix.rs rename to crates/rune-alloc/src/btree/fix.rs index cd1869067..d072e8cd4 100644 --- a/crates/rune-alloc/src/alloc/btree/fix.rs +++ b/crates/rune-alloc/src/btree/fix.rs @@ -1,8 +1,8 @@ +use crate::alloc::Allocator; + use super::map::MIN_LEN; use super::node::{marker, ForceResult::*, Handle, LeftOrRight::*, NodeRef, Root}; -use crate::alloc::Allocator; - impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// Stocks up a possibly underfull node by merging with or stealing from a /// sibling. If successful but at the cost of shrinking the parent node, diff --git a/crates/rune-alloc/src/alloc/btree/map.rs b/crates/rune-alloc/src/btree/map.rs similarity index 99% rename from crates/rune-alloc/src/alloc/btree/map.rs rename to crates/rune-alloc/src/btree/map.rs index 7c2b8cc50..06fafaaa8 100644 --- a/crates/rune-alloc/src/alloc/btree/map.rs +++ b/crates/rune-alloc/src/btree/map.rs @@ -10,10 +10,15 @@ use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; use core::ops::{Bound, Index, RangeBounds}; -#[cfg(test)] -use crate::alloc::testing::*; -use crate::alloc::TryExtend; use crate::ptr; +#[cfg(test)] +use crate::testing::*; + +use crate::alloc::{AllocError, Allocator, Global}; +use crate::boxed::Box; +use crate::clone::TryClone; +use crate::error::{CustomError, Error}; +use crate::iter::{TryExtend, TryFromIteratorIn}; use super::borrow::DormantMutRef; use super::navigate::{LazyLeafRange, LeafRange}; @@ -22,10 +27,6 @@ use super::search::{SearchBound, SearchResult::*}; use super::set_val::SetValZST; use super::Recover; -use crate::alloc::{ - AllocError, Allocator, Box, CustomError, Error, Global, TryClone, TryFromIteratorIn, -}; - pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry}; mod entry; @@ -802,7 +803,8 @@ impl BTreeMap { /// Basic usage: /// /// ``` - /// use rune_alloc::{BTreeMap, Global}; + /// use rune_alloc::BTreeMap; + /// use rune_alloc::alloc::Global; /// /// let mut map = BTreeMap::new_in(Global); /// @@ -961,7 +963,7 @@ impl BTreeMap { /// /// assert_eq!(*map.get(&1).unwrap(), "first"); /// assert_eq!(*map.get(&2).unwrap(), "b"); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn first_entry(&mut self) -> Option> { let (map, dormant_map) = DormantMutRef::new(self); @@ -1232,7 +1234,8 @@ impl BTreeMap { /// Basic usage: /// /// ``` - /// use rune_alloc::{BTreeMap, CustomError}; + /// use rune_alloc::BTreeMap; + /// use rune_alloc::error::CustomError; /// /// let mut map = BTreeMap::new(); /// assert_eq!(map.try_insert_or(37, "a").unwrap(), &"a"); @@ -1362,7 +1365,8 @@ impl BTreeMap { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeMap, IteratorExt}; + /// use rune_alloc::BTreeMap; + /// use rune_alloc::prelude::*; /// /// let mut map: BTreeMap = (0..8).map(|x| (x, x*10)).try_collect()?; /// // Keep only the elements with even-numbered keys. @@ -1409,7 +1413,7 @@ impl BTreeMap { /// assert_eq!(a[&3], "d"); // Note: "c" has been overwritten. /// assert_eq!(a[&4], "e"); /// assert_eq!(a[&5], "f"); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn try_append(&mut self, other: &mut Self) -> Result<(), AllocError> where @@ -1475,7 +1479,7 @@ impl BTreeMap { /// } /// /// assert_eq!(Some((&5, &"b")), map.range(4..).next()); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn range(&self, range: R) -> Range<'_, K, V> where @@ -1736,7 +1740,8 @@ impl BTreeMap { /// Splitting a map into even and odd keys, reusing the original map: /// /// ``` - /// use rune_alloc::{Vec, BTreeMap, IteratorExt}; + /// use rune_alloc::{Vec, BTreeMap}; + /// use rune_alloc::prelude::*; /// /// let mut map: BTreeMap = (0..8).map(|x| (x, x)).try_collect()?; /// let evens: BTreeMap<_, _> = map.extract_if(|k, _v| k % 2 == 0).try_collect()?; @@ -1783,7 +1788,8 @@ impl BTreeMap { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeMap, Vec, IteratorExt}; + /// use rune_alloc::{BTreeMap, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut a = BTreeMap::new(); /// a.try_insert(2, "b")?; @@ -1807,7 +1813,8 @@ impl BTreeMap { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeMap, Vec, IteratorExt}; + /// use rune_alloc::{BTreeMap, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut a = BTreeMap::new(); /// a.try_insert(1, "hello"); @@ -2761,7 +2768,8 @@ impl BTreeMap { /// Basic usage: /// /// ``` - /// use rune_alloc::{BTreeMap, Vec, IteratorExt}; + /// use rune_alloc::{BTreeMap, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut a = BTreeMap::new(); /// a.try_insert(1, "hello")?; @@ -2782,7 +2790,8 @@ impl BTreeMap { /// Basic usage: /// /// ``` - /// use rune_alloc::{BTreeMap, Vec, String, TryClone}; + /// use rune_alloc::{BTreeMap, Vec, String}; + /// use rune_alloc::prelude::*; /// /// let mut a = BTreeMap::new(); /// a.try_insert(1, String::try_from("hello")?)?; diff --git a/crates/rune-alloc/src/alloc/btree/map/entry.rs b/crates/rune-alloc/src/btree/map/entry.rs similarity index 96% rename from crates/rune-alloc/src/alloc/btree/map/entry.rs rename to crates/rune-alloc/src/btree/map/entry.rs index 3d64b69af..e67990a9d 100644 --- a/crates/rune-alloc/src/alloc/btree/map/entry.rs +++ b/crates/rune-alloc/src/btree/map/entry.rs @@ -8,9 +8,9 @@ use super::super::borrow::DormantMutRef; use super::super::node::{marker, Handle, NodeRef}; use super::BTreeMap; -#[cfg(test)] -use crate::alloc::testing::*; use crate::alloc::AllocError; +#[cfg(test)] +use crate::testing::*; use Entry::*; @@ -124,7 +124,7 @@ impl<'a, K: Ord, V, A: Allocator> Entry<'a, K, V, A> { /// map.entry("poneyland").or_try_insert(12)?; /// /// assert_eq!(map["poneyland"], 12); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn or_try_insert(self, default: V) -> Result<&'a mut V, AllocError> { match self { @@ -148,7 +148,7 @@ impl<'a, K: Ord, V, A: Allocator> Entry<'a, K, V, A> { /// map.entry("poneyland").or_try_insert_with(|| s)?; /// /// assert_eq!(map["poneyland"], "hoho".to_string()); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn or_try_insert_with V>(self, default: F) -> Result<&'a mut V, AllocError> { match self { @@ -175,7 +175,7 @@ impl<'a, K: Ord, V, A: Allocator> Entry<'a, K, V, A> { /// map.entry("poneyland").or_try_insert_with_key(|key| key.chars().count())?; /// /// assert_eq!(map["poneyland"], 9); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` #[inline] pub fn or_try_insert_with_key V>( @@ -228,7 +228,7 @@ impl<'a, K: Ord, V, A: Allocator> Entry<'a, K, V, A> { /// .and_modify(|e| { *e += 1 }) /// .or_try_insert(42)?; /// assert_eq!(map["poneyland"], 43); - /// # Ok::<(), rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn and_modify(self, f: F) -> Self where @@ -257,7 +257,7 @@ impl<'a, K: Ord, V: Default, A: Allocator> Entry<'a, K, V, A> { /// map.entry("poneyland").or_try_default()?; /// /// assert_eq!(map["poneyland"], None); - /// # Ok::<(), rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn or_try_default(self) -> Result<&'a mut V, AllocError> { match self { @@ -317,7 +317,7 @@ impl<'a, K, V, A: Allocator> VacantEntry<'a, K, V, A> { /// } /// /// assert_eq!(map["poneyland"], 37); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn try_insert(mut self, value: V) -> Result<&'a mut V, AllocError> { let out_ptr = match self.handle { @@ -374,7 +374,7 @@ impl<'a, K, V, A: Allocator> OccupiedEntry<'a, K, V, A> { /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); /// map.entry("poneyland").or_try_insert(12)?; /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` #[must_use] pub fn key(&self) -> &K { @@ -399,7 +399,7 @@ impl<'a, K, V, A: Allocator> OccupiedEntry<'a, K, V, A> { /// /// // If now try to get the value, it will panic: /// // println!("{}", map["poneyland"]); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn remove_entry(self) -> (K, V) { self.remove_kv() @@ -419,7 +419,7 @@ impl<'a, K, V, A: Allocator> OccupiedEntry<'a, K, V, A> { /// if let Entry::Occupied(o) = map.entry("poneyland") { /// assert_eq!(o.get(), &12); /// } - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` #[must_use] pub fn get(&self) -> &V { @@ -501,7 +501,7 @@ impl<'a, K, V, A: Allocator> OccupiedEntry<'a, K, V, A> { /// } /// /// assert_eq!(map["poneyland"], 15); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn insert(&mut self, value: V) -> V { mem::replace(self.get_mut(), value) @@ -524,7 +524,7 @@ impl<'a, K, V, A: Allocator> OccupiedEntry<'a, K, V, A> { /// /// // If we try to get "poneyland"'s value, it'll panic: /// // println!("{}", map["poneyland"]); - /// # Ok::<_, rune_alloc::AllocError>(()) + /// # Ok::<_, rune_alloc::Error>(()) /// ``` pub fn remove(self) -> V { self.remove_kv().1 diff --git a/crates/rune-alloc/src/alloc/btree/map/tests.rs b/crates/rune-alloc/src/btree/map/tests.rs similarity index 99% rename from crates/rune-alloc/src/alloc/btree/map/tests.rs rename to crates/rune-alloc/src/btree/map/tests.rs index 2d60dd737..ed1b1bea1 100644 --- a/crates/rune-alloc/src/alloc/btree/map/tests.rs +++ b/crates/rune-alloc/src/btree/map/tests.rs @@ -8,16 +8,16 @@ use core::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use rust_alloc::boxed::Box; use rust_alloc::rc::Rc; -use ::rust_std::cmp::Ordering; -use ::rust_std::iter; -use ::rust_std::mem; -use ::rust_std::ops::Bound::{self, Excluded, Included, Unbounded}; -use ::rust_std::ops::RangeBounds; -use ::rust_std::panic::{catch_unwind, AssertUnwindSafe}; +use std::cmp::Ordering; +use std::iter; +use std::mem; +use std::ops::Bound::{self, Excluded, Included, Unbounded}; +use std::ops::RangeBounds; +use std::panic::{catch_unwind, AssertUnwindSafe}; use rust_alloc::vec; -use crate::alloc::TryClone; +use crate::clone::TryClone; use crate::string::{String, TryToString}; use crate::testing::crash_test::{CrashTestDummy, Panic}; use crate::testing::ord_chaos::{Cyclic3, Governed, Governor}; diff --git a/crates/rune-alloc/src/alloc/btree/mem.rs b/crates/rune-alloc/src/btree/mem.rs similarity index 96% rename from crates/rune-alloc/src/alloc/btree/mem.rs rename to crates/rune-alloc/src/btree/mem.rs index 650c78abc..4aebd2e37 100644 --- a/crates/rune-alloc/src/alloc/btree/mem.rs +++ b/crates/rune-alloc/src/btree/mem.rs @@ -25,7 +25,7 @@ pub(crate) fn replace( impl Drop for PanicGuard { fn drop(&mut self) { - ::rust_std::process::abort() + crate::abort() } } diff --git a/crates/rune-alloc/src/alloc/btree/merge_iter.rs b/crates/rune-alloc/src/btree/merge_iter.rs similarity index 100% rename from crates/rune-alloc/src/alloc/btree/merge_iter.rs rename to crates/rune-alloc/src/btree/merge_iter.rs diff --git a/crates/rune-alloc/src/alloc/btree/mod.rs b/crates/rune-alloc/src/btree/mod.rs similarity index 100% rename from crates/rune-alloc/src/alloc/btree/mod.rs rename to crates/rune-alloc/src/btree/mod.rs diff --git a/crates/rune-alloc/src/alloc/btree/navigate.rs b/crates/rune-alloc/src/btree/navigate.rs similarity index 100% rename from crates/rune-alloc/src/alloc/btree/navigate.rs rename to crates/rune-alloc/src/btree/navigate.rs diff --git a/crates/rune-alloc/src/alloc/btree/node.rs b/crates/rune-alloc/src/btree/node.rs similarity index 100% rename from crates/rune-alloc/src/alloc/btree/node.rs rename to crates/rune-alloc/src/btree/node.rs diff --git a/crates/rune-alloc/src/alloc/btree/node/tests.rs b/crates/rune-alloc/src/btree/node/tests.rs similarity index 99% rename from crates/rune-alloc/src/alloc/btree/node/tests.rs rename to crates/rune-alloc/src/btree/node/tests.rs index 4932088c3..2f81ab740 100644 --- a/crates/rune-alloc/src/alloc/btree/node/tests.rs +++ b/crates/rune-alloc/src/btree/node/tests.rs @@ -2,8 +2,8 @@ use core::fmt; use rust_alloc::string::String; -use crate::alloc::testing::*; use crate::alloc::Global; +use crate::testing::*; use super::super::navigate; use super::*; diff --git a/crates/rune-alloc/src/alloc/btree/remove.rs b/crates/rune-alloc/src/btree/remove.rs similarity index 100% rename from crates/rune-alloc/src/alloc/btree/remove.rs rename to crates/rune-alloc/src/btree/remove.rs index 3d343d71d..c279099c7 100644 --- a/crates/rune-alloc/src/alloc/btree/remove.rs +++ b/crates/rune-alloc/src/btree/remove.rs @@ -1,8 +1,8 @@ +use crate::alloc::Allocator; + use super::map::MIN_LEN; use super::node::{marker, ForceResult::*, Handle, LeftOrRight::*, NodeRef}; -use crate::alloc::Allocator; - impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInternal>, marker::KV> { /// Removes a key-value pair from the tree, and returns that pair, as well as /// the leaf edge corresponding to that former pair. It's possible this empties diff --git a/crates/rune-alloc/src/alloc/btree/search.rs b/crates/rune-alloc/src/btree/search.rs similarity index 100% rename from crates/rune-alloc/src/alloc/btree/search.rs rename to crates/rune-alloc/src/btree/search.rs diff --git a/crates/rune-alloc/src/alloc/btree/set.rs b/crates/rune-alloc/src/btree/set.rs similarity index 98% rename from crates/rune-alloc/src/alloc/btree/set.rs rename to crates/rune-alloc/src/btree/set.rs index 7e803b8fa..4c4f7de37 100644 --- a/crates/rune-alloc/src/alloc/btree/set.rs +++ b/crates/rune-alloc/src/btree/set.rs @@ -13,9 +13,12 @@ use super::merge_iter::MergeIterInner; use super::set_val::SetValZST; use super::Recover; +use crate::alloc::{AllocError, Allocator, Global}; +use crate::clone::TryClone; +use crate::error::Error; +use crate::iter::{TryExtend, TryFromIteratorIn}; #[cfg(test)] -use crate::alloc::testing::*; -use crate::alloc::{AllocError, Allocator, Error, Global, TryClone, TryExtend, TryFromIteratorIn}; +use crate::testing::*; /// An ordered set based on a B-Tree. /// @@ -371,7 +374,8 @@ impl BTreeSet { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeSet, Global}; + /// use rune_alloc::BTreeSet; + /// use rune_alloc::alloc::Global; /// /// let mut set: BTreeSet = BTreeSet::new_in(Global); /// ``` @@ -427,7 +431,8 @@ impl BTreeSet { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeSet, Vec, IteratorExt}; + /// use rune_alloc::{BTreeSet, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut a = BTreeSet::new(); /// a.try_insert(1)?; @@ -495,7 +500,8 @@ impl BTreeSet { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeSet, Vec, IteratorExt}; + /// use rune_alloc::{BTreeSet, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut a = BTreeSet::new(); /// a.try_insert(1)?; @@ -526,7 +532,8 @@ impl BTreeSet { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeSet, Vec, IteratorExt}; + /// use rune_alloc::{BTreeSet, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut a = BTreeSet::new(); /// a.try_insert(1)?; @@ -592,7 +599,8 @@ impl BTreeSet { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeSet, Vec, IteratorExt}; + /// use rune_alloc::{BTreeSet, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut a = BTreeSet::new(); /// a.try_insert(1)?; @@ -616,7 +624,8 @@ impl BTreeSet { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeSet, Vec, IteratorExt}; + /// use rune_alloc::{BTreeSet, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut v = BTreeSet::new(); /// v.try_insert(1)?; @@ -1203,7 +1212,8 @@ impl BTreeSet { /// Splitting a set into even and odd values, reusing the original set: /// /// ``` - /// use rune_alloc::{BTreeSet, Vec, IteratorExt}; + /// use rune_alloc::{BTreeSet, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut set: BTreeSet = (0..8).try_collect()?; /// let evens: BTreeSet<_> = set.extract_if(|v| v % 2 == 0).try_collect()?; @@ -1303,7 +1313,8 @@ impl IntoIterator for BTreeSet { /// # Examples /// /// ``` - /// use rune_alloc::{BTreeSet, Vec, IteratorExt}; + /// use rune_alloc::{BTreeSet, Vec}; + /// use rune_alloc::prelude::*; /// /// let set = BTreeSet::try_from([1, 2, 3, 4])?; /// diff --git a/crates/rune-alloc/src/alloc/btree/set/tests.rs b/crates/rune-alloc/src/btree/set/tests.rs similarity index 99% rename from crates/rune-alloc/src/alloc/btree/set/tests.rs rename to crates/rune-alloc/src/btree/set/tests.rs index d5e7c8eaf..3ef39fb3b 100644 --- a/crates/rune-alloc/src/alloc/btree/set/tests.rs +++ b/crates/rune-alloc/src/btree/set/tests.rs @@ -9,7 +9,7 @@ use core::hash::{Hash, Hasher}; use core::ops::Bound::{Excluded, Included}; use rust_alloc::format; -use rust_std::panic::{catch_unwind, AssertUnwindSafe}; +use std::panic::{catch_unwind, AssertUnwindSafe}; use super::*; diff --git a/crates/rune-alloc/src/alloc/btree/set_val.rs b/crates/rune-alloc/src/btree/set_val.rs similarity index 88% rename from crates/rune-alloc/src/alloc/btree/set_val.rs rename to crates/rune-alloc/src/btree/set_val.rs index 4970eadcf..4d725f7c3 100644 --- a/crates/rune-alloc/src/alloc/btree/set_val.rs +++ b/crates/rune-alloc/src/btree/set_val.rs @@ -1,4 +1,5 @@ -use crate::alloc::{Error, TryClone}; +use crate::clone::TryClone; +use crate::error::Error; /// Zero-Sized Type (ZST) for internal `BTreeSet` values. /// Used instead of `()` to differentiate between: diff --git a/crates/rune-alloc/src/alloc/btree/split.rs b/crates/rune-alloc/src/btree/split.rs similarity index 100% rename from crates/rune-alloc/src/alloc/btree/split.rs rename to crates/rune-alloc/src/btree/split.rs diff --git a/crates/rune-alloc/src/alloc/try_clone.rs b/crates/rune-alloc/src/clone.rs similarity index 75% rename from crates/rune-alloc/src/alloc/try_clone.rs rename to crates/rune-alloc/src/clone.rs index da3377f03..5a9cd1bbb 100644 --- a/crates/rune-alloc/src/alloc/try_clone.rs +++ b/crates/rune-alloc/src/clone.rs @@ -1,4 +1,7 @@ -use crate::alloc::Error; +use crate::error::Error; + +#[doc(inline)] +pub use rune_alloc_macros::TryClone; /// Fallible `Clone` trait. pub trait TryClone: Sized { @@ -22,7 +25,6 @@ pub trait TryClone: Sized { pub trait TryCopy: TryClone {} impl TryClone for &T { - #[inline] fn try_clone(&self) -> Result { Ok(*self) } @@ -55,6 +57,8 @@ macro_rules! impl_copy { }; } +impl_copy!(char); +impl_copy!(bool); impl_copy!(usize); impl_copy!(isize); impl_copy!(u8); @@ -83,6 +87,47 @@ impl_copy!(::core::num::NonZeroI32); impl_copy!(::core::num::NonZeroI64); impl_copy!(::core::num::NonZeroI128); +impl TryClone for ::core::result::Result +where + T: TryClone, + E: TryClone, +{ + #[inline] + fn try_clone(&self) -> Result { + Ok(match self { + Ok(value) => Ok(value.try_clone()?), + Err(value) => Err(value.try_clone()?), + }) + } +} + +impl TryClone for ::core::option::Option +where + T: TryClone, +{ + #[inline] + fn try_clone(&self) -> Result { + Ok(match self { + Some(value) => Some(value.try_clone()?), + None => None, + }) + } +} + +#[cfg(feature = "alloc")] +impl TryClone for ::rust_alloc::sync::Arc { + fn try_clone(&self) -> Result { + Ok(self.clone()) + } +} + +#[cfg(feature = "alloc")] +impl TryClone for ::rust_alloc::rc::Rc { + fn try_clone(&self) -> Result { + Ok(self.clone()) + } +} + #[cfg(feature = "alloc")] impl TryClone for ::rust_alloc::boxed::Box where @@ -135,3 +180,9 @@ where Ok(out) } } + +impl TryClone for crate::path::PathBuf { + fn try_clone(&self) -> Result { + Ok(self.clone()) + } +} diff --git a/crates/rune-alloc/src/error.rs b/crates/rune-alloc/src/error.rs new file mode 100644 index 000000000..c5a5d22ca --- /dev/null +++ b/crates/rune-alloc/src/error.rs @@ -0,0 +1,77 @@ +use core::fmt; + +use crate::alloc::AllocError; + +/// An error type returned when a custom error is available alongside an allocation error. +#[derive(Debug)] +pub enum CustomError { + /// Custom error being returned. + Custom(E), + /// Try reserve error being returned. + Error(Error), +} + +impl From for CustomError { + fn from(error: Error) -> Self { + CustomError::Error(error) + } +} + +impl From for CustomError { + fn from(error: AllocError) -> Self { + CustomError::Error(Error::from(error)) + } +} + +/// The error type for methods which allocate or reserve. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] +pub enum Error { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + #[doc(hidden)] + CapacityOverflow, + + /// Error when computing layout. + #[doc(hidden)] + LayoutError, + + /// Error during internal formatting. + #[doc(hidden)] + FormatError, + + /// The memory allocator returned an error + #[doc(hidden)] + AllocError { + /// The layout of the allocation request that failed. + error: AllocError, + }, +} + +impl From for Error { + #[inline] + fn from(error: AllocError) -> Self { + Error::AllocError { error } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::CapacityOverflow => write!(f, "Capacity overflow"), + Error::LayoutError => write!(f, "Layout error"), + Error::FormatError => write!(f, "Format error"), + Error::AllocError { error } => error.fmt(f), + } + } +} + +#[cfg(feature = "std")] +impl ::std::error::Error for Error { + fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> { + match self { + Error::AllocError { error } => Some(error), + _ => None, + } + } +} diff --git a/crates/rune-alloc/src/fmt.rs b/crates/rune-alloc/src/fmt.rs index e52be7336..43ac8d000 100644 --- a/crates/rune-alloc/src/fmt.rs +++ b/crates/rune-alloc/src/fmt.rs @@ -1,8 +1,10 @@ //! Built-in formatting utilities. -use core::fmt; +use core::fmt::{self, Arguments}; -use crate::alloc::Error; +use crate::borrow::TryToOwned; +use crate::error::Error; +use crate::string::String; /// Fallible write formatting implementation. pub trait TryWrite { @@ -20,15 +22,17 @@ pub trait TryWrite { /// # Examples /// /// ``` - /// use std::fmt::{Error, Write}; + /// use rune_alloc::fmt::TryWrite; + /// use rune_alloc::{String, Error}; /// - /// fn writer(f: &mut W, s: &str) -> Result<(), Error> { - /// f.write_str(s) + /// fn writer(f: &mut W, s: &str) -> Result<(), Error> { + /// f.try_write_str(s) /// } /// /// let mut buf = String::new(); - /// writer(&mut buf, "hola").unwrap(); + /// writer(&mut buf, "hola")?; /// assert_eq!(&buf, "hola"); + /// # Ok::<_, rune_alloc::Error>(()) /// ``` fn try_write_str(&mut self, s: &str) -> Result<(), Error>; @@ -46,16 +50,18 @@ pub trait TryWrite { /// # Examples /// /// ``` - /// use std::fmt::{Error, Write}; + /// use rune_alloc::fmt::TryWrite; + /// use rune_alloc::{String, Error}; /// - /// fn writer(f: &mut W, c: char) -> Result<(), Error> { - /// f.write_char(c) + /// fn writer(f: &mut W, c: char) -> Result<(), Error> { + /// f.try_write_char(c) /// } /// /// let mut buf = String::new(); - /// writer(&mut buf, 'a').unwrap(); - /// writer(&mut buf, 'b').unwrap(); + /// writer(&mut buf, 'a')?; + /// writer(&mut buf, 'b')?; /// assert_eq!(&buf, "ab"); + /// # Ok::<_, rune_alloc::Error>(()) /// ``` #[inline] fn try_write_char(&mut self, c: char) -> Result<(), Error> { @@ -98,7 +104,9 @@ pub trait TryWrite { error: None, }; - fmt::write(&mut writer, args).unwrap(); + if let Err(fmt::Error) = fmt::write(&mut writer, args) { + return Err(Error::FormatError); + } if let Some(error) = writer.error { Err(error) @@ -107,3 +115,58 @@ pub trait TryWrite { } } } + +/// The `format` function takes an [`Arguments`] struct and returns the +/// resulting formatted string. +/// +/// The [`Arguments`] instance can be created with the [`format_args!`] macro. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use rune_alloc::fmt; +/// +/// let s = fmt::try_format(format_args!("Hello, {}!", "world"))?; +/// assert_eq!(s, "Hello, world!"); +/// # Ok::<_, rune_alloc::Error>(()) +/// ``` +/// +/// Please note that using [`format!`] might be preferable. +/// Example: +/// +/// ``` +/// use rune_alloc::try_format; +/// +/// let s = try_format!("Hello, {}!", "world"); +/// assert_eq!(s, "Hello, world!"); +/// # Ok::<_, rune_alloc::Error>(()) +/// ``` +/// +/// [`format_args!`]: core::format_args +/// [`format!`]: crate::format +#[inline] +pub fn try_format(args: Arguments<'_>) -> Result { + #[cfg(rune_nightly)] + fn estimated_capacity(args: &Arguments<'_>) -> usize { + args.estimated_capacity() + } + + #[cfg(not(rune_nightly))] + fn estimated_capacity(_: &Arguments<'_>) -> usize { + 0 + } + + fn format_inner(args: Arguments<'_>) -> Result { + let capacity = estimated_capacity(&args); + let mut output = String::try_with_capacity(capacity)?; + output.write_fmt(args)?; + Ok(output) + } + + match args.as_str() { + Some(string) => string.try_to_owned(), + None => format_inner(args), + } +} diff --git a/crates/rune-alloc/src/alloc/hashbrown/map.rs b/crates/rune-alloc/src/hashbrown/map.rs similarity index 99% rename from crates/rune-alloc/src/alloc/hashbrown/map.rs rename to crates/rune-alloc/src/hashbrown/map.rs index 57ae648e6..dd15f9b3b 100644 --- a/crates/rune-alloc/src/alloc/hashbrown/map.rs +++ b/crates/rune-alloc/src/hashbrown/map.rs @@ -7,10 +7,13 @@ use core::marker::PhantomData; use core::mem; use core::ops::Index; -#[cfg(test)] -use crate::alloc::testing::*; use crate::alloc::{into_ok, into_ok_try}; -use crate::alloc::{Allocator, CustomError, Error, Global, TryClone, TryExtend, TryFromIteratorIn}; +use crate::alloc::{Allocator, Global}; +use crate::clone::TryClone; +use crate::error::{CustomError, Error}; +use crate::iter::{TryExtend, TryFromIteratorIn}; +#[cfg(test)] +use crate::testing::*; use super::raw::{Bucket, RawDrain, RawIntoIter, RawIter, RawTable}; use super::{Equivalent, ErrorOrInsertSlot, HasherFn}; @@ -190,7 +193,8 @@ pub type Hasher = ahash::AHasher; /// A `HashMap` with fixed list of elements can be initialized from an array: /// /// ``` -/// use rune_alloc::{HashMap, IteratorExt}; +/// use rune_alloc::HashMap; +/// use rune_alloc::prelude::*; /// /// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)] /// .iter().cloned().try_collect()?; @@ -383,7 +387,8 @@ impl HashMap { /// # Examples /// /// ``` - /// use rune_alloc::{HashMap, Global}; + /// use rune_alloc::HashMap; + /// use rune_alloc::alloc::Global; /// /// let mut map = HashMap::new_in(Global); /// @@ -428,7 +433,8 @@ impl HashMap { /// # Examples /// /// ``` - /// use rune_alloc::{HashMap, Global}; + /// use rune_alloc::HashMap; + /// use rune_alloc::alloc::Global; /// /// let mut map = HashMap::try_with_capacity_in(5, Global)?; /// @@ -613,7 +619,8 @@ impl HashMap { /// # Examples /// /// ``` - /// use rune_alloc::{HashMap, Global}; + /// use rune_alloc::HashMap; + /// use rune_alloc::alloc::Global; /// use rune_alloc::hash_map::DefaultHashBuilder; /// /// let s = DefaultHashBuilder::default(); @@ -961,7 +968,8 @@ impl HashMap { /// # Examples /// /// ``` - /// use rune_alloc::{HashMap, Vec, IteratorExt}; + /// use rune_alloc::{HashMap, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).try_collect()?; /// assert_eq!(map.len(), 8); @@ -1009,7 +1017,7 @@ impl HashMap { /// # Examples /// /// ``` - /// use rune_alloc::{HashMap, Vec, IteratorExt}; + /// use rune_alloc::{HashMap, Vec}; /// use rune_alloc::prelude::*; /// /// let mut map: HashMap = (0..8).map(|x| (x, x)).try_collect()?; @@ -1082,7 +1090,8 @@ impl HashMap { /// # Examples /// /// ``` - /// use rune_alloc::{HashMap, Vec, IteratorExt}; + /// use rune_alloc::{HashMap, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut map = HashMap::new(); /// map.try_insert("a", 1)?; @@ -1111,7 +1120,8 @@ impl HashMap { /// # Examples /// /// ``` - /// use rune_alloc::{HashMap, Vec, IteratorExt}; + /// use rune_alloc::{HashMap, Vec}; + /// use rune_alloc::prelude::*; /// /// let mut map = HashMap::new(); /// map.try_insert("a", 1)?; @@ -1929,7 +1939,8 @@ where /// Basic usage: /// /// ``` - /// use rune_alloc::{HashMap, CustomError}; + /// use rune_alloc::HashMap; + /// use rune_alloc::error::CustomError; /// use rune_alloc::hash_map::OccupiedError; /// /// let mut map = HashMap::new(); @@ -4828,7 +4839,7 @@ impl, Q: ?Sized + Debug, V, S, A: Allocator> Debug /// /// ``` /// use rune_alloc::hash_map::{HashMap, OccupiedError}; -/// use rune_alloc::CustomError; +/// use rune_alloc::error::CustomError; /// /// let mut map: HashMap<_, _> = [("a", 10), ("b", 20)].try_into()?; /// @@ -7024,14 +7035,14 @@ mod test_map { use core::ptr::NonNull; use core::sync::atomic::{AtomicI8, Ordering}; - use ::rust_std::borrow::ToOwned; - use ::rust_std::cell::RefCell; - use ::rust_std::collections::hash_map::DefaultHasher; - use ::rust_std::ops::AddAssign; - use ::rust_std::thread; - use ::rust_std::usize; - use ::rust_std::vec::Vec; - use ::rust_std::{format, println}; + use std::borrow::ToOwned; + use std::cell::RefCell; + use std::collections::hash_map::DefaultHasher; + use std::ops::AddAssign; + use std::thread; + use std::usize; + use std::vec::Vec; + use std::{format, println}; use ::rust_alloc::string::{String, ToString}; use ::rust_alloc::sync::Arc; @@ -7042,11 +7053,14 @@ mod test_map { use super::Entry::{Occupied, Vacant}; use super::{EntryRef, HashMap, RawEntryMut}; - use crate::alloc::testing::*; use crate::alloc::{into_ok, into_ok_try}; - use crate::alloc::{AllocError, Allocator, Error, Global, TryClone, TryExtend}; + use crate::alloc::{AllocError, Allocator, Global}; + use crate::clone::TryClone; + use crate::error::Error; + use crate::iter::TryExtend; + use crate::testing::*; - ::rust_std::thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } + std::thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } #[test] fn test_zero_capacities() { @@ -8502,7 +8516,7 @@ mod test_map { #[test] #[cfg_attr(miri, ignore)] // FIXME: no OOM signalling (https://github.com/rust-lang/miri/issues/613) fn test_try_reserve() { - use crate::Error::{AllocError, CapacityOverflow}; + use crate::error::Error::{AllocError, CapacityOverflow}; const MAX_ISIZE: usize = isize::MAX as usize; @@ -8822,7 +8836,7 @@ mod test_map { } } impl TryClone for CheckedDrop { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> Result { Ok(Self { panic_in_drop: self.panic_in_drop, dropped: self.dropped, diff --git a/crates/rune-alloc/src/alloc/hashbrown/mod.rs b/crates/rune-alloc/src/hashbrown/mod.rs similarity index 96% rename from crates/rune-alloc/src/alloc/hashbrown/mod.rs rename to crates/rune-alloc/src/hashbrown/mod.rs index 8c754e202..e3eb4fde8 100644 --- a/crates/rune-alloc/src/alloc/hashbrown/mod.rs +++ b/crates/rune-alloc/src/hashbrown/mod.rs @@ -1,17 +1,26 @@ #![allow(clippy::missing_safety_doc)] pub mod raw; + +#[cfg(feature = "serde")] +mod serde; + mod scopeguard; +#[doc(hidden)] pub use self::map::HashMap; +#[doc(hidden)] pub mod map; +#[doc(hidden)] pub use self::set::HashSet; +#[doc(hidden)] pub mod set; -use super::CustomError; use core::marker::PhantomData; +use crate::error::CustomError; + /// Trait used to implement custom equality implementations which are not solely /// based on traits. pub trait EqFn { diff --git a/crates/rune-alloc/src/alloc/hashbrown/raw/bitmask.rs b/crates/rune-alloc/src/hashbrown/raw/bitmask.rs similarity index 100% rename from crates/rune-alloc/src/alloc/hashbrown/raw/bitmask.rs rename to crates/rune-alloc/src/hashbrown/raw/bitmask.rs diff --git a/crates/rune-alloc/src/alloc/hashbrown/raw/generic.rs b/crates/rune-alloc/src/hashbrown/raw/generic.rs similarity index 100% rename from crates/rune-alloc/src/alloc/hashbrown/raw/generic.rs rename to crates/rune-alloc/src/hashbrown/raw/generic.rs diff --git a/crates/rune-alloc/src/alloc/hashbrown/raw/mod.rs b/crates/rune-alloc/src/hashbrown/raw/mod.rs similarity index 99% rename from crates/rune-alloc/src/alloc/hashbrown/raw/mod.rs rename to crates/rune-alloc/src/hashbrown/raw/mod.rs index d1c808121..f73190523 100644 --- a/crates/rune-alloc/src/alloc/hashbrown/raw/mod.rs +++ b/crates/rune-alloc/src/hashbrown/raw/mod.rs @@ -8,16 +8,18 @@ use core::{hint, ptr}; use crate::hashbrown::scopeguard::{guard, ScopeGuard}; +use crate::alloc::{Allocator, Global, SizedTypeProperties}; +use crate::clone::TryClone; #[cfg(rune_nightly)] -use crate::alloc::TryCopy; -use crate::alloc::{Allocator, CustomError, Error, Global, SizedTypeProperties, TryClone}; +use crate::clone::TryCopy; +use crate::error::{CustomError, Error}; // Branch prediction hint. This is currently only available on nightly but it // consistently improves performance by 10-15%. use crate::hint::{likely, unlikely}; use crate::ptr::invalid_mut; #[cfg(test)] -use crate::alloc::testing::*; +use crate::testing::*; use super::{EqFn, ErrorOrInsertSlot, HasherFn}; @@ -432,6 +434,7 @@ impl Bucket { /// ``` /// use core::hash::{BuildHasher, Hash}; /// use core::convert::Infallible; + /// /// use rune_alloc::hashbrown::raw::{Bucket, RawTable}; /// /// type NewHashBuilder = core::hash::BuildHasherDefault; @@ -592,6 +595,7 @@ impl Bucket { /// ``` /// use core::hash::{BuildHasher, Hash}; /// use core::convert::Infallible; + /// /// use rune_alloc::hashbrown::raw::{Bucket, RawTable}; /// /// type NewHashBuilder = core::hash::BuildHasherDefault; @@ -645,6 +649,7 @@ impl Bucket { /// ``` /// use core::hash::{BuildHasher, Hash}; /// use core::convert::Infallible; + /// /// use rune_alloc::hashbrown::raw::{Bucket, RawTable}; /// /// type NewHashBuilder = core::hash::BuildHasherDefault; @@ -4163,8 +4168,8 @@ mod test_map { use crate::alloc::{AllocError, Allocator}; use ::rust_alloc::sync::Arc; use ::rust_alloc::vec::Vec; - use ::rust_std::thread; use core::sync::atomic::{AtomicI8, Ordering}; + use std::thread; struct MyAllocInner { drop_count: Arc, @@ -4177,7 +4182,7 @@ mod test_map { impl Drop for MyAllocInner { fn drop(&mut self) { - ::rust_std::println!("MyAlloc freed."); + std::println!("MyAlloc freed."); self.drop_count.fetch_sub(1, Ordering::SeqCst); } } diff --git a/crates/rune-alloc/src/alloc/hashbrown/raw/neon.rs b/crates/rune-alloc/src/hashbrown/raw/neon.rs similarity index 100% rename from crates/rune-alloc/src/alloc/hashbrown/raw/neon.rs rename to crates/rune-alloc/src/hashbrown/raw/neon.rs diff --git a/crates/rune-alloc/src/alloc/hashbrown/raw/sse2.rs b/crates/rune-alloc/src/hashbrown/raw/sse2.rs similarity index 100% rename from crates/rune-alloc/src/alloc/hashbrown/raw/sse2.rs rename to crates/rune-alloc/src/hashbrown/raw/sse2.rs diff --git a/crates/rune-alloc/src/alloc/hashbrown/scopeguard.rs b/crates/rune-alloc/src/hashbrown/scopeguard.rs similarity index 100% rename from crates/rune-alloc/src/alloc/hashbrown/scopeguard.rs rename to crates/rune-alloc/src/hashbrown/scopeguard.rs diff --git a/crates/rune-alloc/src/hashbrown/serde.rs b/crates/rune-alloc/src/hashbrown/serde.rs new file mode 100644 index 000000000..fef3e60c1 --- /dev/null +++ b/crates/rune-alloc/src/hashbrown/serde.rs @@ -0,0 +1,227 @@ +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::alloc::Allocator; + + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + + use serde::de::{Deserialize, Deserializer, Error, 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::try_with_capacity_and_hasher_in( + size_hint::cautious(map.size_hint()), + S::default(), + A::default(), + ) + .map_err(M::Error::custom)?; + + while let Some((key, value)) = map.next_entry()? { + values.try_insert(key, value).map_err(M::Error::custom)?; + } + + Ok(values) + } + } + + let visitor = MapVisitor { + marker: PhantomData, + }; + deserializer.deserialize_map(visitor) + } + } +} + +mod set { + use crate::alloc::Allocator; + + use core::fmt; + use core::hash::{BuildHasher, Hash}; + use core::marker::PhantomData; + use serde::de::{Deserialize, Deserializer, Error, 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::try_with_capacity_and_hasher_in( + size_hint::cautious(seq.size_hint()), + S::default(), + A::default(), + ) + .map_err(M::Error::custom)?; + + while let Some(value) = seq.next_element()? { + values.try_insert(value).map_err(M::Error::custom)?; + } + + 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 + .try_reserve(size_hint::cautious(seq.size_hint())) + .map_err(M::Error::custom)?; + + while let Some(value) = seq.next_element()? { + self.0.try_insert(value).map_err(M::Error::custom)?; + } + + Ok(()) + } + } + + deserializer.deserialize_seq(SeqInPlaceVisitor(place)) + } + } +} diff --git a/crates/rune-alloc/src/alloc/hashbrown/set.rs b/crates/rune-alloc/src/hashbrown/set.rs similarity index 99% rename from crates/rune-alloc/src/alloc/hashbrown/set.rs rename to crates/rune-alloc/src/hashbrown/set.rs index 91d6e23b6..4d1c6649a 100644 --- a/crates/rune-alloc/src/alloc/hashbrown/set.rs +++ b/crates/rune-alloc/src/hashbrown/set.rs @@ -4,9 +4,13 @@ use core::iter::{Chain, FusedIterator}; use super::Equivalent; +use crate::alloc::{Allocator, Global}; +use crate::borrow::TryToOwned; +use crate::clone::TryClone; +use crate::error::Error; +use crate::iter::{TryExtend, TryFromIteratorIn}; #[cfg(test)] -use crate::alloc::testing::*; -use crate::alloc::{Allocator, Error, Global, TryClone, TryExtend, TryFromIteratorIn, TryToOwned}; +use crate::testing::*; use super::map::{self, DefaultHashBuilder, ExtractIfInner, HashMap, Keys}; use super::raw::RawTable; @@ -245,7 +249,9 @@ impl HashSet { /// # Examples /// /// ``` - /// use rune_alloc::{HashSet, Global}; + /// use rune_alloc::HashSet; + /// use rune_alloc::alloc::Global; + /// /// let set: HashSet = HashSet::new_in(Global); /// ``` #[cfg_attr(feature = "inline-more", inline)] @@ -637,7 +643,8 @@ where /// # Examples /// /// ``` - /// use rune_alloc::{HashSet, Global}; + /// use rune_alloc::HashSet; + /// use rune_alloc::alloc::Global; /// use rune_alloc::hash_map::DefaultHashBuilder; /// /// let s = DefaultHashBuilder::default(); @@ -2844,7 +2851,7 @@ mod test_set { #[test] fn test_const_with_hasher() { use core::hash::BuildHasher; - use rust_std::collections::hash_map::DefaultHasher; + use std::collections::hash_map::DefaultHasher; #[derive(Clone)] struct MyHasher; diff --git a/crates/rune-alloc/src/iter/ext.rs b/crates/rune-alloc/src/iter/ext.rs index a8a12a38a..94db17fed 100644 --- a/crates/rune-alloc/src/iter/ext.rs +++ b/crates/rune-alloc/src/iter/ext.rs @@ -1,4 +1,7 @@ -use crate::alloc::{Allocator, Error, Global, TryFromIteratorIn}; +use crate::alloc::{Allocator, Global}; +use crate::clone::TryClone; +use crate::error::Error; +use crate::iter::{TryCloned, TryFromIteratorIn, TryJoin}; /// Iterator extension trait. pub trait IteratorExt: Iterator + self::sealed::Sealed { @@ -19,6 +22,77 @@ pub trait IteratorExt: Iterator + self::sealed::Sealed { { TryFromIteratorIn::try_from_iter_in(self, alloc) } + + /// Try to join the given value. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::String; + /// use rune_alloc::prelude::*; + /// + /// let values = ["foo", "bar"]; + /// let string: String = values.into_iter().try_join("/")?; + /// assert_eq!(string, "foo/bar"); + /// + /// let values = ["foo", "bar"]; + /// let string: String = values.into_iter().try_join('/')?; + /// assert_eq!(string, "foo/bar"); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + fn try_join(self, sep: S) -> Result + where + Self: Sized, + J: TryJoin, + { + J::try_join_in(self, sep, Global) + } + + /// Try to join the given value. + fn try_join_in(self, sep: S, alloc: A) -> Result + where + Self: Sized, + J: TryJoin, + { + J::try_join_in(self, sep, alloc) + } + + /// Creates an iterator which [`try_clone`]s all of its elements. + /// + /// This is useful when you have an iterator over `&T`, but you need an + /// iterator over `T`. + /// + /// There is no guarantee whatsoever about the `try_clone` method actually + /// being called *or* optimized away. So code should not depend on either. + /// + /// [`try_clone`]: TryClone::try_clone + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use rune_alloc::{try_vec, Vec}; + /// use rune_alloc::prelude::*; + /// + /// let a = [1, 2, 3]; + /// + /// let v_cloned: Vec<_> = a.iter().try_cloned().try_collect::>()??; + /// + /// // cloned is the same as .map(|&x| x), for integers + /// let v_map: Vec<_> = a.iter().map(|&x| x).try_collect()?; + /// + /// assert_eq!(v_cloned, [1, 2, 3]); + /// assert_eq!(v_map, [1, 2, 3]); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + fn try_cloned<'a, T: 'a>(self) -> TryCloned + where + Self: Sized + Iterator, + T: TryClone, + { + TryCloned::new(self) + } } impl IteratorExt for I where I: Iterator {} diff --git a/crates/rune-alloc/src/iter/join.rs b/crates/rune-alloc/src/iter/join.rs new file mode 100644 index 000000000..44893d088 --- /dev/null +++ b/crates/rune-alloc/src/iter/join.rs @@ -0,0 +1,10 @@ +use crate::alloc::Allocator; +use crate::error::Error; + +/// Helper trait for joining iterators. +pub trait TryJoin: Sized { + /// Try to join the given value in the given allocator. + fn try_join_in(iter: I, sep: S, alloc: A) -> Result + where + I: IntoIterator; +} diff --git a/crates/rune-alloc/src/iter/mod.rs b/crates/rune-alloc/src/iter/mod.rs index 5295e824d..117efa54e 100644 --- a/crates/rune-alloc/src/iter/mod.rs +++ b/crates/rune-alloc/src/iter/mod.rs @@ -2,3 +2,15 @@ pub use self::ext::IteratorExt; mod ext; + +pub use self::try_cloned::TryCloned; +mod try_cloned; + +pub use self::try_extend::TryExtend; +mod try_extend; + +pub use self::try_from_iterator::{TryFromIterator, TryFromIteratorIn}; +mod try_from_iterator; + +pub use self::join::TryJoin; +pub(crate) mod join; diff --git a/crates/rune-alloc/src/iter/try_cloned.rs b/crates/rune-alloc/src/iter/try_cloned.rs new file mode 100644 index 000000000..a6d8c79d6 --- /dev/null +++ b/crates/rune-alloc/src/iter/try_cloned.rs @@ -0,0 +1,36 @@ +use crate::clone::TryClone; +use crate::error::Error; + +/// An iterator that clones the elements of an underlying iterator. +/// +/// This `struct` is created by the [`try_cloned`] method on [`IteratorExt`]. +/// See its documentation for more. +/// +/// [`try_cloned`]: crate::iter::IteratorExt::try_cloned +/// [`IteratorExt`]: crate::iter::IteratorExt +pub struct TryCloned { + it: I, +} + +impl TryCloned { + pub(in crate::iter) fn new(it: I) -> Self { + Self { it } + } +} + +impl<'a, I, T: 'a> Iterator for TryCloned +where + I: Iterator, + T: TryClone, +{ + type Item = Result; + + #[inline] + fn next(&mut self) -> Option { + Some(self.it.next()?.try_clone()) + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } +} diff --git a/crates/rune-alloc/src/alloc/try_extend.rs b/crates/rune-alloc/src/iter/try_extend.rs similarity index 96% rename from crates/rune-alloc/src/alloc/try_extend.rs rename to crates/rune-alloc/src/iter/try_extend.rs index 96cb0f50b..08c9c97c9 100644 --- a/crates/rune-alloc/src/alloc/try_extend.rs +++ b/crates/rune-alloc/src/iter/try_extend.rs @@ -1,4 +1,4 @@ -use super::Error; +use crate::error::Error; /// Extend a collection with the contents of an iterator. /// @@ -82,7 +82,8 @@ pub trait TryExtend { /// Basic usage: /// /// ``` - /// use rune_alloc::{String, TryExtend}; + /// use rune_alloc::String; + /// use rune_alloc::prelude::*; /// /// // You can extend a String with some chars: /// let mut message = String::try_from("abc")?; diff --git a/crates/rune-alloc/src/alloc/try_from_iterator.rs b/crates/rune-alloc/src/iter/try_from_iterator.rs similarity index 97% rename from crates/rune-alloc/src/alloc/try_from_iterator.rs rename to crates/rune-alloc/src/iter/try_from_iterator.rs index be9db0e22..f36e96491 100644 --- a/crates/rune-alloc/src/alloc/try_from_iterator.rs +++ b/crates/rune-alloc/src/iter/try_from_iterator.rs @@ -1,4 +1,5 @@ -use super::{Allocator, Error, Global}; +use crate::alloc::{Allocator, Global}; +use crate::error::Error; /// Conversion from an [`Iterator`] within a custom allocator `A`. /// diff --git a/crates/rune-alloc/src/lib.rs b/crates/rune-alloc/src/lib.rs index 7eb8061bf..6337c5acb 100644 --- a/crates/rune-alloc/src/lib.rs +++ b/crates/rune-alloc/src/lib.rs @@ -43,7 +43,7 @@ #![allow(clippy::drop_non_drop)] #[cfg(feature = "std")] -extern crate std as rust_std; +extern crate std; #[cfg(feature = "alloc")] extern crate alloc as rust_alloc; @@ -53,47 +53,87 @@ extern crate alloc as rust_alloc; #[cfg(not(feature = "alloc"))] compile_error!("The `alloc` feature is currently required to build rune-alloc, but will change for parts of rune in the future."); +/// A `Result` aliased specialized towards an allocation [`Error`]. +pub type Result = core::result::Result; + +#[cfg(feature = "std")] +pub use std::path; +#[cfg(not(feature = "std"))] +pub mod path; + +#[cfg(not(feature = "std"))] +mod no_std; +#[cfg(not(feature = "std"))] +pub use self::no_std::abort; + +#[cfg(feature = "std")] +pub use std::process::abort; + +#[cfg(feature = "serde")] +mod serde; + #[macro_use] mod public_macros; #[macro_use] mod macros; -pub use self::alloc::boxed::{self, Box}; -pub use self::alloc::btree::{map as btree_map, map::BTreeMap}; -pub use self::alloc::btree::{set as btree_set, set::BTreeSet}; -pub use self::alloc::hashbrown; -pub use self::alloc::hashbrown::{map as hash_map, map::HashMap}; -pub use self::alloc::hashbrown::{set as hash_set, set::HashSet}; -pub use self::alloc::str; -pub use self::alloc::string::{self, String, TryToString}; -pub use self::alloc::vec::{self, Vec}; -pub use self::alloc::vec_deque::{self, VecDeque}; -pub use self::alloc::{ - AllocError, Allocator, CustomError, Error, Global, TryClone, TryExtend, TryFromIterator, - TryFromIteratorIn, TryToOwned, -}; -pub(crate) mod alloc; - -pub use self::iter::IteratorExt; +pub use self::error::Error; +pub mod error; + +pub mod str; + +pub(crate) mod raw_vec; + +pub use self::boxed::Box; +pub mod boxed; + +pub use self::btree::{map as btree_map, map::BTreeMap}; +pub use self::btree::{set as btree_set, set::BTreeSet}; +pub(crate) mod btree; + +pub use self::hashbrown::{map as hash_map, map::HashMap}; +pub use self::hashbrown::{set as hash_set, set::HashSet}; +pub mod hashbrown; + +pub use self::vec::Vec; +pub mod vec; + +pub use self::vec_deque::VecDeque; +pub mod vec_deque; + +pub use self::string::String; +pub mod string; + +pub mod alloc; + +pub mod clone; + +pub mod borrow; + pub mod iter; -pub use self::fmt::TryWrite; pub mod fmt; +mod option; + pub(crate) mod hint; pub(crate) mod ptr; -pub(crate) mod slice; +#[doc(hidden)] +pub mod slice; pub mod prelude { //! Prelude for common traits used in combination with this crate which //! matches the behavior of the std prelude. - pub use crate::{ - IteratorExt, TryClone, TryExtend, TryFromIterator, TryFromIteratorIn, TryToOwned, - TryToString, - }; + pub use crate::borrow::TryToOwned; + pub use crate::clone::{TryClone, TryCopy}; + pub use crate::iter::{IteratorExt, TryExtend, TryFromIterator, TryFromIteratorIn}; + pub use crate::option::OptionExt; + pub use crate::string::TryToString; } +pub mod limit; + #[cfg(test)] mod testing; diff --git a/crates/rune-alloc/src/limit.rs b/crates/rune-alloc/src/limit.rs new file mode 100644 index 000000000..ae33f26dd --- /dev/null +++ b/crates/rune-alloc/src/limit.rs @@ -0,0 +1,121 @@ +//! Memory limits for Rune. +//! +//! This module contains methods which allows for limiting the memory use of the +//! virtual machine to abide by the specified budget. +//! +//! By default memory limits are disabled, but can be enabled by wrapping your +//! function call or future in [with]. + +#[cfg_attr(feature = "std", path = "limit/std.rs")] +mod no_std; + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +use pin_project::pin_project; + +/// Something being budgeted. +#[pin_project] +pub struct Memory { + /// The current budget. + budget: usize, + /// The thing being budgeted. + #[pin] + value: T, +} + +/// Wrap the given value with a memory limit. +/// +/// # Examples +/// +/// ``` +/// use rune_alloc::limit; +/// use rune_alloc::Vec; +/// +/// let f = limit::with(1024, || { +/// let mut vec = Vec::::try_with_capacity(256)?; +/// +/// for n in 0..256u32 { +/// vec.try_push(n)?; +/// } +/// +/// Ok::<_, rune_alloc::Error>(vec.into_iter().sum::()) +/// }); +/// +/// let sum = f.call()?; +/// assert_eq!(sum, 32640); +/// # Ok::<_, rune_alloc::Error>(()) +/// ``` +/// +/// Overloading the limit. Note that this happens because while the vector is +/// growing it might both over-allocate, and hold onto two allocations +/// simultaneously. +/// +/// ``` +/// use rune_alloc::limit; +/// use rune_alloc::Vec; +/// +/// let f = limit::with(1024, || { +/// let mut vec = Vec::::new(); +/// +/// for n in 0..256u32 { +/// vec.try_push(n)?; +/// } +/// +/// Ok::<_, rune_alloc::Error>(vec.into_iter().sum::()) +/// }); +/// +/// assert!(f.call().is_err()); +/// ``` +pub fn with(budget: usize, value: T) -> Memory { + Memory { budget, value } +} + +/// Take memory from the current budget. +#[inline(never)] +pub(crate) fn take(amount: usize) -> bool { + self::no_std::rune_memory_take(amount) +} + +/// Release memory from the current budget. +#[inline(never)] +pub(crate) fn release(amount: usize) { + self::no_std::rune_memory_release(amount); +} + +#[repr(transparent)] +struct MemoryGuard(usize); + +impl Drop for MemoryGuard { + fn drop(&mut self) { + let _ = self::no_std::rune_memory_replace(self.0); + } +} + +impl Memory +where + T: FnOnce() -> O, +{ + /// Call the wrapped function. + pub fn call(self) -> O { + let _guard = MemoryGuard(self::no_std::rune_memory_replace(self.budget)); + (self.value)() + } +} + +impl Future for Memory +where + T: Future, +{ + type Output = T::Output; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = self.project(); + + let _guard = MemoryGuard(self::no_std::rune_memory_replace(*this.budget)); + let poll = this.value.poll(cx); + *this.budget = self::no_std::rune_memory_get(); + poll + } +} diff --git a/crates/rune-alloc/src/limit/no_std.rs b/crates/rune-alloc/src/limit/no_std.rs new file mode 100644 index 000000000..b56b7a3b4 --- /dev/null +++ b/crates/rune-alloc/src/limit/no_std.rs @@ -0,0 +1,23 @@ +pub(super) fn rune_memory_take(amount: usize) -> bool { + // SAFETY: implementor is expected to have read the documentation and + // implemented this correctly. + unsafe { crate::no_std::__rune_alloc_memory_take(amount) } +} + +pub(super) fn rune_memory_release(amount: usize) { + // SAFETY: implementor is expected to have read the documentation and + // implemented this correctly. + unsafe { crate::no_std::__rune_alloc_memory_release(amount) } +} + +pub(super) fn rune_memory_get() -> usize { + // SAFETY: implementor is expected to have read the documentation and + // implemented this correctly. + unsafe { crate::no_std::__rune_alloc_memory_get() } +} + +pub(super) fn rune_memory_replace(value: usize) -> usize { + // SAFETY: implementor is expected to have read the documentation and + // implemented this correctly. + unsafe { crate::no_std::__rune_alloc_memory_replace(value) } +} diff --git a/crates/rune-alloc/src/limit/std.rs b/crates/rune-alloc/src/limit/std.rs new file mode 100644 index 000000000..f89ad924d --- /dev/null +++ b/crates/rune-alloc/src/limit/std.rs @@ -0,0 +1,37 @@ +use core::cell::Cell; + +std::thread_local!(static MEMORY: Cell = Cell::new(usize::MAX)); + +pub(super) fn rune_memory_take(amount: usize) -> bool { + MEMORY.with(|tls| { + let v = tls.get(); + + if v == usize::MAX { + true + } else if v >= amount { + tls.set(v - amount); + true + } else { + tls.set(0); + false + } + }) +} + +pub(super) fn rune_memory_release(amount: usize) { + MEMORY.with(|tls| { + let v = tls.get(); + + if v != usize::MAX { + tls.set(v.saturating_add(amount)); + } + }) +} + +pub(super) fn rune_memory_get() -> usize { + MEMORY.with(|tls| tls.get()) +} + +pub(super) fn rune_memory_replace(value: usize) -> usize { + MEMORY.with(|tls| tls.replace(value)) +} diff --git a/crates/rune-alloc/src/no_std.rs b/crates/rune-alloc/src/no_std.rs new file mode 100644 index 000000000..43775a0c3 --- /dev/null +++ b/crates/rune-alloc/src/no_std.rs @@ -0,0 +1,41 @@ +// In no-std environments, the implementor must define these functions. +// +// Normally these make use of thread-local storage, but if you want them to be +// completed disabled simply return dummy values or store it in static storage +// (if single threaded). +extern "C" { + /// Take the given amount of memory from the current budget. Return `false` + /// if the budget has been breached, or `true` otherwise. + /// + /// If this is called before `rune_memory_set` then it should usually just + /// return `true`. + pub(crate) fn __rune_alloc_memory_take(amount: usize) -> bool; + + /// Release the given amount of memory to the current budget. + pub(crate) fn __rune_alloc_memory_release(amount: usize); + + /// Get the remaining memory budget for the current thread. + pub(crate) fn __rune_alloc_memory_get() -> usize; + + /// Replace the memory budget for the current thread and return the one + /// which was previously set. + pub(crate) fn __rune_alloc_memory_replace(value: usize) -> usize; + + /// Abort the current process. + /// + /// In microcontrollers this might be implemented as an infinite loop. + pub(crate) fn __rune_alloc_abort() -> !; +} + +/// Terminates the process in an abnormal fashion. +/// +/// The function will never return and will immediately terminate the current +/// process in a platform specific "abnormal" manner. +/// +/// Note that because this function never returns, and that it terminates the +/// process, no destructors on the current stack or any other thread's stack +/// will be run. +pub fn abort() -> ! { + // SAFETY: hook is always safe to call. + unsafe { __rune_alloc_abort() } +} diff --git a/crates/rune-alloc/src/option/ext.rs b/crates/rune-alloc/src/option/ext.rs new file mode 100644 index 000000000..6f5270df2 --- /dev/null +++ b/crates/rune-alloc/src/option/ext.rs @@ -0,0 +1,35 @@ +use crate::clone::TryClone; +use crate::error::Error; + +/// Extensions to `Option`. +pub trait OptionExt { + /// Maps an `Option<&T>` to an `Option` by cloning the contents of the + /// option. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::prelude::*; + /// + /// let x = 12u32; + /// let opt_x = Some(&x); + /// assert_eq!(opt_x, Some(&12)); + /// let cloned = opt_x.try_cloned()?; + /// assert_eq!(cloned, Some(12u32)); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + #[must_use = "`self` will be dropped if the result is not used"] + fn try_cloned(self) -> Result, Error>; +} + +impl OptionExt for Option<&T> +where + T: TryClone, +{ + fn try_cloned(self) -> Result, Error> { + Ok(match self { + Some(value) => Some(value.try_clone()?), + None => None, + }) + } +} diff --git a/crates/rune-alloc/src/option/mod.rs b/crates/rune-alloc/src/option/mod.rs new file mode 100644 index 000000000..af2b3fe88 --- /dev/null +++ b/crates/rune-alloc/src/option/mod.rs @@ -0,0 +1,2 @@ +pub use self::ext::OptionExt; +pub(crate) mod ext; diff --git a/crates/rune/src/no_std/path.rs b/crates/rune-alloc/src/path.rs similarity index 66% rename from crates/rune/src/no_std/path.rs rename to crates/rune-alloc/src/path.rs index e7a970159..c64422ebd 100644 --- a/crates/rune/src/no_std/path.rs +++ b/crates/rune-alloc/src/path.rs @@ -1,11 +1,10 @@ +use core::borrow::Borrow; use core::clone::Clone; use core::convert::AsRef; use core::fmt; use core::ops::Deref; -use ::rust_alloc::borrow::Borrow; -use ::rust_alloc::borrow::ToOwned; -use ::rust_alloc::boxed::Box; +use rust_alloc::boxed::Box; #[derive(Debug)] #[repr(transparent)] @@ -15,34 +14,38 @@ pub struct Path { impl Path { #[inline] - pub(crate) fn new

(path: &P) -> &Path + pub fn new

(path: &P) -> &Path where P: ?Sized + AsRef, { unsafe { &*(path.as_ref() as *const _ as *const Path) } } - pub(crate) fn display(&self) -> Display<'_> { + pub fn display(&self) -> Display<'_> { Display { _path: self } } - pub(crate) fn join

(&self, _: P) -> PathBuf + pub fn join

(&self, _: P) -> PathBuf where P: AsRef, { PathBuf } - pub(crate) fn with_extension(&self, _: S) -> PathBuf + pub fn with_extension(&self, _: S) -> PathBuf where S: AsRef, { PathBuf } - pub(crate) fn is_file(&self) -> bool { + pub fn is_file(&self) -> bool { false } + + pub fn to_path_buf(&self) -> PathBuf { + PathBuf + } } impl AsRef for str { @@ -52,7 +55,7 @@ impl AsRef for str { } } -pub(crate) struct Display<'a> { +pub struct Display<'a> { _path: &'a Path, } @@ -69,43 +72,26 @@ impl AsRef for Path { } } -impl Clone for Box { - fn clone(&self) -> Box { - todo!() - } -} - -impl From<&Path> for Box { - #[inline] - fn from(p: &Path) -> Self { - let rw = Box::into_raw(Box::<[u8]>::from(p.inner.to_vec())) as *mut Path; - unsafe { Box::from_raw(rw) } - } -} - -impl ToOwned for Path { - type Owned = PathBuf; - - #[inline] - fn to_owned(&self) -> Self::Owned { - PathBuf - } -} - #[derive(Debug, Clone)] pub struct PathBuf; impl PathBuf { - pub(crate) fn push

(&mut self, _: P) + pub fn push

(&mut self, _: P) where P: AsRef, { // Do nothing } - pub(crate) fn pop(&mut self) -> bool { + pub fn pop(&mut self) -> bool { true } + + pub fn into_boxed_path(self) -> Box { + let ptr = Box::into_raw(Box::<[u8]>::default()) as *mut Path; + // SAFETY: Layout of Path and [u8] is the same. + unsafe { Box::from_raw(ptr) } + } } impl AsRef for PathBuf { @@ -137,3 +123,15 @@ impl Deref for PathBuf { Path::new("") } } + +impl Clone for Box { + fn clone(&self) -> Self { + self.to_path_buf().into_boxed_path() + } +} + +impl From<&Path> for Box { + fn from(path: &Path) -> Self { + path.to_path_buf().into_boxed_path() + } +} diff --git a/crates/rune-alloc/src/public_macros.rs b/crates/rune-alloc/src/public_macros.rs index 390d60986..1634aa0d3 100644 --- a/crates/rune-alloc/src/public_macros.rs +++ b/crates/rune-alloc/src/public_macros.rs @@ -9,7 +9,7 @@ macro_rules! try_vec { ); ($($x:expr),+ $(,)?) => ( - $crate::vec::into_vec( + $crate::slice::into_vec( // This rustc_box is not required, but it produces a dramatic improvement in compile // time when constructing arrays with many elements. $crate::boxed::Box::try_from([$($x),+])? @@ -17,14 +17,50 @@ macro_rules! try_vec { ); } +/// Creates a `String` using interpolation of runtime expressions. +/// +/// The first argument `try_format!` receives is a format string. This must be a +/// string literal. The power of the formatting string is in the `{}`s +/// contained. +/// +/// Additional parameters passed to `try_format!` replace the `{}`s within the +/// formatting string in the order given unless named or positional parameters +/// are used; see [`std::fmt`] for more information. +/// +/// A common use for `try_format!` is concatenation and interpolation of +/// strings. The same convention is used with [`print!`] and [`write!`] macros, +/// depending on the intended destination of the string. +/// +/// To convert a single value to a string, use the [`try_to_string`] method. +/// This will use the [`Display`] formatting trait. +/// +/// [`std::fmt`]: ../std/fmt/index.html +/// [`print!`]: ../std/macro.print.html +/// [`write!`]: core::write +/// [`try_to_string`]: crate::string::TryToString +/// [`Display`]: core::fmt::Display +/// +/// # Panics +/// +/// `try_format!` panics if a formatting trait implementation returns an error. This +/// indicates an incorrect implementation since `fmt::Write for String` never +/// returns an error itself. +/// +/// # Examples +/// +/// ``` +/// use rune_alloc::try_format; +/// +/// try_format!("test"); +/// try_format!("hello {}", "world!"); +/// try_format!("x = {}, y = {y}", 10, y = 30); +/// let (x, y) = (1, 2); +/// try_format!("{x} + {y} = 3"); +/// # Ok::<_, rune_alloc::Error>(()) +/// ``` #[macro_export] macro_rules! try_format { - ($($tt:tt)*) => {{ - (|| { - use $crate::fmt::TryWrite; - let mut s = $crate::alloc::string::String::new(); - core::write!(s, $($tt)*)?; - Ok::<_, $crate::Error>(s) - })() - }}; + ($($tt:tt)*) => { + $crate::fmt::try_format(format_args!($($tt)*))? + }; } diff --git a/crates/rune-alloc/src/alloc/raw_vec.rs b/crates/rune-alloc/src/raw_vec.rs similarity index 99% rename from crates/rune-alloc/src/alloc/raw_vec.rs rename to crates/rune-alloc/src/raw_vec.rs index 405f103c9..94841955e 100644 --- a/crates/rune-alloc/src/alloc/raw_vec.rs +++ b/crates/rune-alloc/src/raw_vec.rs @@ -3,10 +3,11 @@ use core::cmp; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::slice; -use crate::alloc::boxed::Box; -use crate::alloc::{AllocError, Allocator, Error, Global, SizedTypeProperties}; -use crate::ptr::Unique; -use crate::ptr::{self, NonNull}; +use crate::alloc::SizedTypeProperties; +use crate::alloc::{AllocError, Allocator, Global}; +use crate::boxed::Box; +use crate::error::Error; +use crate::ptr::{self, NonNull, Unique}; enum AllocInit { /// The contents of the new memory are uninitialized. diff --git a/crates/rune-alloc/src/serde/de.rs b/crates/rune-alloc/src/serde/de.rs new file mode 100644 index 000000000..71e5be784 --- /dev/null +++ b/crates/rune-alloc/src/serde/de.rs @@ -0,0 +1,176 @@ +use core::fmt; +use core::marker::PhantomData; + +use serde::de::{Deserialize, Deserializer, Error, SeqAccess, Visitor}; + +use crate::boxed::Box; +use crate::vec::Vec; + +mod size_hint { + use core::cmp; + use core::mem; + + pub fn cautious(hint: Option) -> usize { + const MAX_PREALLOC_BYTES: usize = 1024 * 1024; + + if mem::size_of::() == 0 { + 0 + } else { + cmp::min( + hint.unwrap_or(0), + MAX_PREALLOC_BYTES / mem::size_of::(), + ) + } + } +} + +mod seed { + use serde::de::{Deserialize, DeserializeSeed, Deserializer}; + + /// A DeserializeSeed helper for implementing deserialize_in_place Visitors. + /// + /// Wraps a mutable reference and calls deserialize_in_place on it. + pub struct InPlaceSeed<'a, T: 'a>(pub &'a mut T); + + impl<'a, 'de, T> DeserializeSeed<'de> for InPlaceSeed<'a, T> + where + T: Deserialize<'de>, + { + type Value = (); + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + T::deserialize_in_place(deserializer, self.0) + } + } +} + +macro_rules! forwarded_impl { + ( + $(#[doc = $doc:tt])* + <$($id:ident),*>, $ty:ty, $func:expr + ) => { + $(#[doc = $doc])* + impl<'de $(, $id : Deserialize<'de>,)*> Deserialize<'de> for $ty { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value = Deserialize::deserialize(deserializer)?; + $func(value).map_err(D::Error::custom) + } + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +forwarded_impl!(, Box, Box::try_new); + +impl<'de, T> Deserialize<'de> for Vec +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct VecVisitor { + marker: PhantomData, + } + + impl<'de, T> Visitor<'de> for VecVisitor + where + T: Deserialize<'de>, + { + type Value = Vec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let capacity = size_hint::cautious::(seq.size_hint()); + let mut values = Vec::::try_with_capacity(capacity).map_err(A::Error::custom)?; + + while let Some(value) = seq.next_element()? { + values.try_push(value).map_err(A::Error::custom)?; + } + + Ok(values) + } + } + + let visitor = VecVisitor { + marker: PhantomData, + }; + + deserializer.deserialize_seq(visitor) + } + + fn deserialize_in_place(deserializer: D, place: &mut Self) -> Result<(), D::Error> + where + D: Deserializer<'de>, + { + struct VecInPlaceVisitor<'a, T: 'a>(&'a mut Vec); + + impl<'a, 'de, T> Visitor<'de> for VecInPlaceVisitor<'a, T> + where + T: Deserialize<'de>, + { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let hint = size_hint::cautious::(seq.size_hint()); + + if let Some(additional) = hint.checked_sub(self.0.len()) { + self.0.try_reserve(additional).map_err(A::Error::custom)?; + } + + for i in 0..self.0.len() { + let next = { + let next_place = seed::InPlaceSeed(&mut self.0[i]); + seq.next_element_seed(next_place)? + }; + + if next.is_none() { + self.0.truncate(i); + return Ok(()); + } + } + + while let Some(value) = seq.next_element()? { + self.0.try_push(value).map_err(A::Error::custom)?; + } + + Ok(()) + } + } + + deserializer.deserialize_seq(VecInPlaceVisitor(place)) + } +} + +impl<'de, T> Deserialize<'de> for Box<[T]> +where + T: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Vec::::deserialize(deserializer)? + .try_into_boxed_slice() + .map_err(D::Error::custom) + } +} diff --git a/crates/rune-alloc/src/serde/mod.rs b/crates/rune-alloc/src/serde/mod.rs new file mode 100644 index 000000000..d7e9daaa1 --- /dev/null +++ b/crates/rune-alloc/src/serde/mod.rs @@ -0,0 +1,2 @@ +mod de; +mod ser; diff --git a/crates/rune-alloc/src/serde/ser.rs b/crates/rune-alloc/src/serde/ser.rs new file mode 100644 index 000000000..bf2a909af --- /dev/null +++ b/crates/rune-alloc/src/serde/ser.rs @@ -0,0 +1,47 @@ +use serde::ser::{Serialize, Serializer}; + +use crate::borrow::{Cow, TryToOwned}; +use crate::boxed::Box; +use crate::btree::set::BTreeSet; +use crate::vec::Vec; + +macro_rules! deref_impl { + ( + $(#[doc = $doc:tt])* + <$($desc:tt)+ + ) => { + $(#[doc = $doc])* + impl <$($desc)+ { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + (**self).serialize(serializer) + } + } + }; +} + +deref_impl!( Serialize for Box where T: Serialize); +deref_impl!( Serialize for Cow<'_, T> where T: Serialize + TryToOwned); + +macro_rules! seq_impl { + ($ty:ident ) => { + impl Serialize for $ty + where + T: Serialize, + { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.collect_seq(self) + } + } + } +} + +seq_impl!(BTreeSet); +seq_impl!(Vec); diff --git a/crates/rune-alloc/src/slice.rs b/crates/rune-alloc/src/slice.rs index ff17e2ee5..55f965bf7 100644 --- a/crates/rune-alloc/src/slice.rs +++ b/crates/rune-alloc/src/slice.rs @@ -1,6 +1,12 @@ pub(crate) use self::iter::{RawIter, RawIterMut}; pub(crate) mod iter; +use crate::alloc::{Allocator, Global}; +use crate::borrow::TryToOwned; +use crate::clone::TryClone; +use crate::error::Error; +use crate::{Box, Vec}; + cfg_if! { if #[cfg(rune_nightly)] { pub(crate) use core::slice::range; @@ -59,3 +65,129 @@ cfg_if! { } } } + +/// Converts `self` into a vector without clones or allocation. +/// +/// The resulting vector can be converted back into a box via +/// `Vec`'s `into_boxed_slice` method. +#[inline] +#[doc(hidden)] +pub fn into_vec(this: Box<[T], A>) -> Vec { + // N.B., see the `hack` module in this file for more details. + hack::into_vec(this) +} + +#[inline] +pub(crate) fn to_vec(s: &[T], alloc: A) -> Result, Error> +where + T: TryClone, +{ + hack::to_vec(s, alloc) +} + +impl TryToOwned for [T] +where + T: TryClone, +{ + type Owned = Vec; + + #[inline] + fn try_to_owned(&self) -> Result { + hack::to_vec(self, Global) + } +} + +// HACK(japaric): With cfg(test) `impl [T]` is not available, these three +// functions are actually methods that are in `impl [T]` but not in +// `core::slice::SliceExt` - we need to supply these functions for the +// `test_permutations` test +pub(crate) mod hack { + use crate::alloc::Allocator; + use crate::clone::TryClone; + use crate::error::Error; + use crate::{Box, Vec}; + + // We shouldn't add inline attribute to this since this is used in `vec!` + // macro mostly and causes perf regression. See #71204 for discussion and + // perf results. + pub(crate) fn into_vec(b: Box<[T], A>) -> Vec { + unsafe { + let len = b.len(); + let (b, alloc) = Box::into_raw_with_allocator(b); + Vec::from_raw_parts_in(b as *mut T, len, len, alloc) + } + } + + #[inline] + pub(crate) fn to_vec( + s: &[T], + alloc: A, + ) -> Result, Error> { + T::to_vec(s, alloc) + } + + pub(crate) trait ConvertVec { + fn to_vec(s: &[Self], alloc: A) -> Result, Error> + where + Self: Sized; + } + + impl ConvertVec for T + where + T: TryClone, + { + #[inline] + fn to_vec(s: &[Self], alloc: A) -> Result, Error> { + struct DropGuard<'a, T, A: Allocator> { + vec: &'a mut Vec, + num_init: usize, + } + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + #[inline] + fn drop(&mut self) { + // SAFETY: + // items were marked initialized in the loop below + unsafe { + self.vec.set_len(self.num_init); + } + } + } + let mut vec = Vec::try_with_capacity_in(s.len(), alloc)?; + let mut guard = DropGuard { + vec: &mut vec, + num_init: 0, + }; + let slots = guard.vec.spare_capacity_mut(); + // .take(slots.len()) is necessary for LLVM to remove bounds checks + // and has better codegen than zip. + for (i, b) in s.iter().enumerate().take(slots.len()) { + guard.num_init = i; + slots[i].write(b.try_clone()?); + } + core::mem::forget(guard); + // SAFETY: + // the vec was allocated and initialized above to at least this length. + unsafe { + vec.set_len(s.len()); + } + Ok(vec) + } + } + + #[cfg(rune_nightly)] + impl ConvertVec for T { + #[inline] + fn to_vec(s: &[Self], alloc: A) -> Result, Error> { + let mut v = Vec::try_with_capacity_in(s.len(), alloc)?; + + // SAFETY: + // allocated above with the capacity of `s`, and initialize to `s.len()` in + // ptr::copy_to_non_overlapping below. + unsafe { + s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); + v.set_len(s.len()); + } + Ok(v) + } + } +} diff --git a/crates/rune-alloc/src/alloc/str.rs b/crates/rune-alloc/src/str.rs similarity index 86% rename from crates/rune-alloc/src/alloc/str.rs rename to crates/rune-alloc/src/str.rs index a26abae1a..5b59c4531 100644 --- a/crates/rune-alloc/src/alloc/str.rs +++ b/crates/rune-alloc/src/str.rs @@ -1,4 +1,8 @@ -use crate::alloc::{Allocator, Box, Error, Global, String, TryToOwned}; +use crate::alloc::{Allocator, Global}; +use crate::borrow::TryToOwned; +use crate::boxed::Box; +use crate::error::Error; +use crate::string::String; /// Converts a boxed slice of bytes to a boxed string slice without checking /// that the string contains valid UTF-8. @@ -33,8 +37,9 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8], A>) -> Box(v: Box<[u8], A>) -> Box(this: Box) -> String { let slice = Box::<[u8], A>::from(this); - let vec = crate::alloc::slice::into_vec(slice); + let vec = crate::slice::into_vec(slice); unsafe { String::::from_utf8_unchecked(vec) } } diff --git a/crates/rune-alloc/src/alloc/string.rs b/crates/rune-alloc/src/string/mod.rs similarity index 89% rename from crates/rune-alloc/src/alloc/string.rs rename to crates/rune-alloc/src/string/mod.rs index 536ff45b0..d59e4f656 100644 --- a/crates/rune-alloc/src/alloc/string.rs +++ b/crates/rune-alloc/src/string/mod.rs @@ -27,16 +27,14 @@ //! use rune_alloc::prelude::*; //! //! let sparkle_heart = rune_alloc::try_vec![240, 159, 146, 150]; -//! -//! // We know these bytes are valid, so we'll use `unwrap()`. -//! let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); +//! let sparkle_heart = String::from_utf8(sparkle_heart)?; //! //! assert_eq!("💖", sparkle_heart); //! //! let bytes = sparkle_heart.into_bytes(); //! //! assert_eq!(bytes, [240, 159, 146, 150]); -//! # Ok::<_, rune_alloc::Error>(()) +//! # Ok::<_, Box>(()) //! ``` #[cfg(feature = "serde")] @@ -45,11 +43,15 @@ mod serde; pub use self::try_to_string::TryToString; pub(crate) mod try_to_string; +#[cfg(feature = "alloc")] +use core::alloc::Layout; use core::borrow::Borrow; use core::cmp::Ordering; use core::fmt; use core::hash; use core::iter::FusedIterator; +#[cfg(feature = "alloc")] +use core::mem::ManuallyDrop; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr; @@ -57,12 +59,17 @@ use core::slice; use core::str::{from_utf8, from_utf8_unchecked, from_utf8_unchecked_mut}; use core::str::{Chars, Utf8Error}; -use super::{Allocator, Box, Error, Global, TryClone, TryExtend, TryFromIteratorIn, Vec}; - -#[cfg(test)] -use crate::alloc::testing::*; +use crate::alloc::{Allocator, Global}; +use crate::borrow::Cow; +use crate::boxed::Box; +use crate::clone::TryClone; +use crate::error::Error; use crate::fmt::TryWrite; +use crate::iter::{TryExtend, TryFromIteratorIn, TryJoin}; use crate::slice::range as slice_range; +#[cfg(test)] +use crate::testing::*; +use crate::vec::Vec; /// A UTF-8–encoded, growable string. /// @@ -108,12 +115,10 @@ use crate::slice::range as slice_range; /// /// // some bytes, in a vector /// let sparkle_heart = rune_alloc::try_vec![240, 159, 146, 150]; -/// -/// // We know these bytes are valid, so we'll use `unwrap()`. -/// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); +/// let sparkle_heart = String::from_utf8(sparkle_heart)?; /// /// assert_eq!("💖", sparkle_heart); -/// # Ok::<_, rune_alloc::Error>(()) +/// # Ok::<_, Box>(()) /// ``` /// /// [`from_utf8`]: String::from_utf8 @@ -343,7 +348,8 @@ use crate::slice::range as slice_range; /// [`try_with_capacity_in`] method to allocate the correct capacity initially: /// /// ``` -/// use rune_alloc::{String, Global}; +/// use rune_alloc::String; +/// use rune_alloc::alloc::Global; /// /// let mut s = String::try_with_capacity_in(25, Global)?; /// @@ -455,6 +461,18 @@ impl String { }) } + /// Convert a [`String`] into a std `String`. + /// + /// The result is allocated on the heap, using the default global allocator + /// so this is a zero-copy operation. + /// + /// The memory previously occupied by this vector will be released. + #[cfg(feature = "alloc")] + pub fn into_std(self) -> ::rust_alloc::string::String { + // SAFETY: The interior vector is valid UTF-8. + unsafe { ::rust_alloc::string::String::from_utf8_unchecked(self.vec.into_std()) } + } + #[cfg(test)] pub fn from(value: &str) -> Self { Self::try_from(value).abort() @@ -549,7 +567,8 @@ impl String { /// # Examples /// /// ``` - /// use rune_alloc::{String, Global}; + /// use rune_alloc::String; + /// use rune_alloc::alloc::Global; /// /// let s = String::new_in(Global); /// ``` @@ -566,7 +585,8 @@ impl String { /// # Examples /// /// ``` - /// use rune_alloc::{String, Global}; + /// use rune_alloc::String; + /// use rune_alloc::alloc::Global; /// /// let s = String::new_in(Global); /// let alloc: &Global = s.allocator(); @@ -595,7 +615,8 @@ impl String { /// # Examples /// /// ``` - /// use rune_alloc::{String, Global}; + /// use rune_alloc::String; + /// use rune_alloc::alloc::Global; /// /// let mut s = String::try_with_capacity_in(10, Global)?; /// @@ -656,25 +677,23 @@ impl String { /// Basic usage: /// /// ``` - /// use rune_alloc::String; + /// use rune_alloc::{try_vec, String}; /// /// // some bytes, in a vector - /// let sparkle_heart = rune_alloc::try_vec![240, 159, 146, 150]; - /// - /// // We know these bytes are valid, so we'll use `unwrap()`. - /// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap(); + /// let sparkle_heart = try_vec![240, 159, 146, 150]; + /// let sparkle_heart = String::from_utf8(sparkle_heart)?; /// /// assert_eq!("💖", sparkle_heart); - /// # Ok::<_, rune_alloc::Error>(()) + /// # Ok::<_, Box>(()) /// ``` /// /// Incorrect bytes: /// /// ``` - /// use rune_alloc::String; + /// use rune_alloc::{try_vec, String}; /// /// // some invalid bytes, in a vector - /// let sparkle_heart = rune_alloc::try_vec![0, 159, 146, 150]; + /// let sparkle_heart = try_vec![0, 159, 146, 150]; /// /// assert!(String::from_utf8(sparkle_heart).is_err()); /// # Ok::<_, rune_alloc::Error>(()) @@ -860,7 +879,8 @@ impl String { /// # Examples /// /// ``` - /// use rune_alloc::{String, Global}; + /// use rune_alloc::String; + /// use rune_alloc::alloc::Global; /// /// let mut s = String::try_with_capacity_in(3, Global)?; /// @@ -885,7 +905,8 @@ impl String { /// # Examples /// /// ``` - /// use rune_alloc::{String, Global}; + /// use rune_alloc::String; + /// use rune_alloc::alloc::Global; /// /// let s = String::try_with_capacity_in(10, Global)?; /// @@ -1025,7 +1046,8 @@ impl String { /// # Examples /// /// ``` - /// use rune_alloc::{String, Global}; + /// use rune_alloc::String; + /// use rune_alloc::alloc::Global; /// /// let mut s = String::try_with_capacity_in(3, Global)?; /// s.try_push_str("abc")?; @@ -1274,7 +1296,8 @@ impl String { /// # Examples /// /// ``` - /// use rune_alloc::{String, Global}; + /// use rune_alloc::String; + /// use rune_alloc::alloc::Global; /// /// let mut s = String::try_with_capacity_in(3, Global)?; /// @@ -1620,7 +1643,7 @@ impl String { #[inline] pub fn try_into_boxed_str(self) -> Result, Error> { let slice = self.vec.try_into_boxed_slice()?; - Ok(unsafe { crate::alloc::str::from_boxed_utf8_unchecked(slice) }) + Ok(unsafe { crate::str::from_boxed_utf8_unchecked(slice) }) } /// Consumes and leaks the `String`, returning a mutable reference to the contents, @@ -1736,7 +1759,25 @@ impl FromUtf8Error { } } -impl Borrow for String { +impl Default for String +where + A: Default, +{ + /// Construct a default string. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::String; + /// let s = String::default(); + /// assert_eq!(s, ""); + /// ``` + fn default() -> Self { + Self::new_in(A::default()) + } +} + +impl Borrow for String { #[inline] fn borrow(&self) -> &str { &self[..] @@ -1756,9 +1797,9 @@ impl fmt::Display for FromUtf16Error { } #[cfg(feature = "std")] -impl ::rust_std::error::Error for FromUtf8Error {} +impl std::error::Error for FromUtf8Error {} #[cfg(feature = "std")] -impl ::rust_std::error::Error for FromUtf16Error {} +impl std::error::Error for FromUtf16Error {} impl TryClone for String { fn try_clone(&self) -> Result { @@ -1830,6 +1871,9 @@ macro_rules! impl_eq { impl_eq! { String, str } impl_eq! { String, &'a str } +impl_eq! { Cow<'a, str>, str } +impl_eq! { Cow<'a, str>, &'b str } +impl_eq! { Cow<'a, str>, String } impl fmt::Display for String { #[inline] @@ -1979,9 +2023,9 @@ impl AsMut for String { } #[cfg(feature = "std")] -impl AsRef<::rust_std::ffi::OsStr> for String { +impl AsRef for String { #[inline] - fn as_ref(&self) -> &::rust_std::ffi::OsStr { + fn as_ref(&self) -> &std::ffi::OsStr { (**self).as_ref() } } @@ -2012,7 +2056,7 @@ impl From> for String { /// # Ok::<_, rune_alloc::Error>(()) /// ``` fn from(s: Box) -> String { - crate::alloc::str::into_string(s) + crate::str::into_string(s) } } @@ -2035,8 +2079,30 @@ impl TryFrom<::rust_alloc::string::String> for String { /// Try to convert a std `String` into a [`String`]. /// /// The result is fallibly allocated on the heap. - fn try_from(s: ::rust_alloc::string::String) -> Result { - Self::try_from(s.as_str()) + /// + /// # Examples + /// + /// ``` + /// let s1 = String::from("Hello World"); + /// let s2 = rune_alloc::String::try_from(s1)?; + /// + /// assert_eq!("Hello World", s2); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + fn try_from(string: ::rust_alloc::string::String) -> Result { + let mut string = ManuallyDrop::new(string.into_bytes()); + + let buf = string.as_mut_ptr(); + let length = string.len(); + let capacity = string.capacity(); + + if let Ok(layout) = Layout::array::(capacity) { + Global.take(layout)?; + } + + // SAFETY: The layout of the string is identical to the std string and + // it uses the same underlying allocator. + unsafe { Ok(String::from_raw_parts_in(buf, length, capacity, Global)) } } } @@ -2056,6 +2122,14 @@ impl TryFrom<&str> for String { /// Converts a `&str` into a [`String`]. /// /// The result is fallibly allocated on the heap. + /// + /// ``` + /// use rune_alloc::String; + /// + /// let s = String::try_from("Hello World")?; + /// assert_eq!(s, "Hello World"); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` fn try_from(s: &str) -> Result { let mut out = String::try_with_capacity_in(s.len(), Global)?; out.try_push_str(s)?; @@ -2063,6 +2137,35 @@ impl TryFrom<&str> for String { } } +impl TryFrom> for String { + type Error = Error; + + /// Converts a `Cow` into a [`String`]. + /// + /// The result is fallibly allocated on the heap unless the values is + /// `Cow::Owned`. + /// + /// ``` + /// use rune_alloc::String; + /// use rune_alloc::borrow::Cow; + /// + /// let s = Cow::Borrowed("Hello World"); + /// let s = String::try_from(s)?; + /// assert_eq!(s, "Hello World"); + /// + /// let s = Cow::Owned(String::try_from("Hello World")?); + /// let s = String::try_from(s)?; + /// assert_eq!(s, "Hello World"); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + fn try_from(s: Cow<'_, str>) -> Result { + match s { + Cow::Borrowed(s) => Self::try_from(s), + Cow::Owned(s) => Ok(s), + } + } +} + impl TryFrom> for Box { type Error = Error; @@ -2071,13 +2174,12 @@ impl TryFrom> for Box { /// # Examples /// /// ``` - /// use rune_alloc::{Box, String}; + /// use rune_alloc::{String, Box}; /// - /// let s1: String = String::try_from("hello world")?; - /// let s2: Box = Box::try_from(s1)?; - /// let s3: String = String::from(s2); + /// let s1: String = String::try_from("Hello World")?; + /// let s2: Box = Box::try_from("Hello World")?; /// - /// assert_eq!("hello world", s3); + /// assert_eq!("Hello World", s2.as_ref()); /// # Ok::<_, rune_alloc::Error>(()) /// ``` fn try_from(s: String) -> Result, Error> { @@ -2085,6 +2187,27 @@ impl TryFrom> for Box { } } +impl TryFrom> for Box { + type Error = Error; + + /// Converts the given [`String`] to a boxed `str` slice that is owned. + /// + /// # Examples + /// + /// ``` + /// use rune_alloc::Box; + /// use rune_alloc::borrow::Cow; + /// + /// let s2: Box = Box::try_from(Cow::Borrowed("Hello World"))?; + /// + /// assert_eq!("Hello World", s2.as_ref()); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + fn try_from(s: Cow<'_, str>) -> Result { + Self::try_from(s.as_ref()) + } +} + impl From> for Vec { /// Converts the given [`String`] to a vector [`Vec`] that holds values of type [`u8`]. /// @@ -2153,10 +2276,11 @@ impl<'a, A: Allocator> Drain<'a, A> { /// /// ``` /// use rune_alloc::String; + /// /// let mut s = String::try_from("abc")?; /// let mut drain = s.drain(..); /// assert_eq!(drain.as_str(), "abc"); - /// let _ = drain.next().unwrap(); + /// assert!(drain.next().is_some()); /// assert_eq!(drain.as_str(), "bc"); /// # Ok::<_, rune_alloc::Error>(()) /// ``` @@ -2238,11 +2362,82 @@ impl TryFromIteratorIn for String { } } +impl<'a, A: Allocator> TryFromIteratorIn<&'a str, A> for String { + /// Construct a string from an iterator of characters. + /// + /// ``` + /// use rune_alloc::String; + /// use rune_alloc::prelude::*; + /// + /// let string = String::try_from_iter(["hello", " ", "world"].into_iter())?; + /// assert_eq!(string, "hello world"); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + fn try_from_iter_in(iter: I, alloc: A) -> Result + where + I: IntoIterator, + { + let mut this = String::new_in(alloc); + this.try_extend(iter)?; + Ok(this) + } +} + +impl TryJoin for String +where + T: AsRef, +{ + fn try_join_in(iter: I, sep: char, alloc: A) -> Result + where + I: IntoIterator, + { + let mut string = String::new_in(alloc); + + let mut iter = iter.into_iter().peekable(); + + while let Some(value) = iter.next() { + string.try_push_str(value.as_ref())?; + + if iter.peek().is_some() { + string.try_push(sep)?; + } + } + + Ok(string) + } +} + +impl TryJoin<&str, T, A> for String +where + T: AsRef, +{ + fn try_join_in(iter: I, sep: &str, alloc: A) -> Result + where + I: IntoIterator, + { + let mut string = String::new_in(alloc); + + let mut iter = iter.into_iter().peekable(); + + while let Some(value) = iter.next() { + string.try_push_str(value.as_ref())?; + + if iter.peek().is_some() { + string.try_push_str(sep)?; + } + } + + Ok(string) + } +} + impl TryExtend for String { /// Extend a string using a character iterator. /// /// ``` - /// use rune_alloc::{String, IteratorExt, TryExtend}; + /// use rune_alloc::String; + /// use rune_alloc::prelude::*; + /// /// let mut string = String::new(); /// string.try_extend(['a', 'b', 'c'])?; /// assert_eq!(string, "abc"); @@ -2257,3 +2452,25 @@ impl TryExtend for String { Ok(()) } } + +impl<'a, A: Allocator> TryExtend<&'a str> for String { + /// Extend a string using a character iterator. + /// + /// ``` + /// use rune_alloc::String; + /// use rune_alloc::prelude::*; + /// + /// let mut string = String::new(); + /// string.try_extend(["hello", " ", "world"])?; + /// assert_eq!(string, "hello world"); + /// # Ok::<_, rune_alloc::Error>(()) + /// ``` + #[inline] + fn try_extend>(&mut self, iter: I) -> Result<(), Error> { + for value in iter { + self.try_push_str(value)?; + } + + Ok(()) + } +} diff --git a/crates/rune-alloc/src/alloc/string/serde.rs b/crates/rune-alloc/src/string/serde.rs similarity index 83% rename from crates/rune-alloc/src/alloc/string/serde.rs rename to crates/rune-alloc/src/string/serde.rs index 67b191c10..68051eccd 100644 --- a/crates/rune-alloc/src/alloc/string/serde.rs +++ b/crates/rune-alloc/src/string/serde.rs @@ -3,7 +3,8 @@ use core::fmt; use serde::de::{self, Error, Unexpected}; use serde::ser; -use crate::{String, TryToOwned, Vec}; +use crate::borrow::{Cow, TryToOwned}; +use crate::{Box, String, Vec}; impl ser::Serialize for String { fn serialize(&self, serializer: S) -> Result @@ -30,6 +31,30 @@ impl<'de> de::Deserialize<'de> for String { } } +impl<'de> de::Deserialize<'de> for Box { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + let string = String::deserialize(deserializer)?; + string.try_into_boxed_str().map_err(D::Error::custom) + } +} + +impl<'de, 'a, T: ?Sized> de::Deserialize<'de> for Cow<'a, T> +where + T: TryToOwned, + T::Owned: de::Deserialize<'de>, +{ + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + T::Owned::deserialize(deserializer).map(Cow::Owned) + } +} + struct StringVisitor; struct StringInPlaceVisitor<'a>(&'a mut String); diff --git a/crates/rune-alloc/src/alloc/string/try_to_string.rs b/crates/rune-alloc/src/string/try_to_string.rs similarity index 88% rename from crates/rune-alloc/src/alloc/string/try_to_string.rs rename to crates/rune-alloc/src/string/try_to_string.rs index 3016b711f..dca0d6ca4 100644 --- a/crates/rune-alloc/src/alloc/string/try_to_string.rs +++ b/crates/rune-alloc/src/string/try_to_string.rs @@ -2,9 +2,11 @@ use core::fmt; +use crate::error::Error; +use crate::fmt::TryWrite; +use crate::string::String; #[cfg(test)] -use crate::alloc::testing::*; -use crate::{Error, String, TryWrite}; +use crate::testing::*; /// A trait for converting a value to a `String`. /// @@ -27,7 +29,8 @@ pub trait TryToString { /// Basic usage: /// /// ``` - /// use rune_alloc::{String, TryToString}; + /// use rune_alloc::String; + /// use rune_alloc::prelude::*; /// /// let i = 5; /// let five = String::try_from("5")?; diff --git a/crates/rune-alloc/src/testing/crash_test.rs b/crates/rune-alloc/src/testing/crash_test.rs index e3cae3acb..14d9399fe 100644 --- a/crates/rune-alloc/src/testing/crash_test.rs +++ b/crates/rune-alloc/src/testing/crash_test.rs @@ -4,7 +4,8 @@ use core::cmp::Ordering; use core::fmt::Debug; use core::sync::atomic::{AtomicUsize, Ordering::SeqCst}; -use crate::alloc::{Error, TryClone}; +use crate::clone::TryClone; +use crate::error::Error; /// A blueprint for crash test dummy instances that monitor particular events. /// Some instances may be configured to panic at some point. diff --git a/crates/rune-alloc/src/testing/mod.rs b/crates/rune-alloc/src/testing/mod.rs index 7a094f8a5..9ed1b79a3 100644 --- a/crates/rune-alloc/src/testing/mod.rs +++ b/crates/rune-alloc/src/testing/mod.rs @@ -1,3 +1,80 @@ pub mod crash_test; pub mod ord_chaos; pub mod rng; + +use core::convert::Infallible; +use core::fmt; + +use crate::alloc::AllocError; +use crate::error::{CustomError, Error}; + +pub(crate) trait CustomTestExt { + fn custom_result(self) -> Result; +} + +impl CustomTestExt for Result> { + fn custom_result(self) -> Result { + match self { + Ok(value) => Ok(value), + Err(CustomError::Custom(error)) => Err(error), + Err(CustomError::Error(error)) => handle_error(error), + } + } +} + +pub(crate) trait TestExt { + fn abort(self) -> T; +} + +impl TestExt for Result { + fn abort(self) -> T { + match self { + Ok(value) => value, + Err(error) => match error {}, + } + } +} + +impl TestExt for Result { + fn abort(self) -> T { + match self { + Ok(value) => value, + Err(error) => handle_error(error), + } + } +} + +impl TestExt for Result { + fn abort(self) -> T { + match self { + Ok(value) => value, + Err(error) => ::rust_alloc::alloc::handle_alloc_error(error.layout), + } + } +} + +impl TestExt for Result> +where + E: fmt::Display, +{ + fn abort(self) -> T { + match self { + Ok(value) => value, + Err(error) => match error { + CustomError::Custom(error) => { + panic!("{}", error) + } + CustomError::Error(error) => handle_error(error), + }, + } + } +} + +fn handle_error(error: Error) -> ! { + match error { + Error::AllocError { error } => ::rust_alloc::alloc::handle_alloc_error(error.layout), + error => { + panic!("{}", error) + } + } +} diff --git a/crates/rune-alloc/src/tests.rs b/crates/rune-alloc/src/tests.rs index 9a3ffc6aa..39c76fce8 100644 --- a/crates/rune-alloc/src/tests.rs +++ b/crates/rune-alloc/src/tests.rs @@ -1,4 +1,5 @@ -use crate::{Error, Vec}; +use crate::error::Error; +use crate::vec::Vec; #[test] fn test_vec_macro() -> Result<(), Error> { diff --git a/crates/rune-alloc/src/alloc/vec/drain.rs b/crates/rune-alloc/src/vec/drain.rs similarity index 99% rename from crates/rune-alloc/src/alloc/vec/drain.rs rename to crates/rune-alloc/src/vec/drain.rs index 750d06d5e..a06420483 100644 --- a/crates/rune-alloc/src/alloc/vec/drain.rs +++ b/crates/rune-alloc/src/vec/drain.rs @@ -1,4 +1,5 @@ -use crate::alloc::{Allocator, Global, SizedTypeProperties}; +use crate::alloc::SizedTypeProperties; +use crate::alloc::{Allocator, Global}; use crate::ptr::{self, NonNull}; use core::fmt; diff --git a/crates/rune-alloc/src/alloc/vec/into_iter.rs b/crates/rune-alloc/src/vec/into_iter.rs similarity index 98% rename from crates/rune-alloc/src/alloc/vec/into_iter.rs rename to crates/rune-alloc/src/vec/into_iter.rs index f6499c732..22a3fb442 100644 --- a/crates/rune-alloc/src/alloc/vec/into_iter.rs +++ b/crates/rune-alloc/src/vec/into_iter.rs @@ -4,9 +4,10 @@ use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; use core::slice::{self}; -use crate::alloc::raw_vec::RawVec; -use crate::alloc::{Allocator, Global, SizedTypeProperties}; +use crate::alloc::SizedTypeProperties; +use crate::alloc::{Allocator, Global}; use crate::ptr::{self, NonNull}; +use crate::raw_vec::RawVec; /// An iterator that moves out of a vector. /// diff --git a/crates/rune-alloc/src/alloc/vec/is_zero.rs b/crates/rune-alloc/src/vec/is_zero.rs similarity index 100% rename from crates/rune-alloc/src/alloc/vec/is_zero.rs rename to crates/rune-alloc/src/vec/is_zero.rs diff --git a/crates/rune-alloc/src/alloc/vec/mod.rs b/crates/rune-alloc/src/vec/mod.rs similarity index 97% rename from crates/rune-alloc/src/alloc/vec/mod.rs rename to crates/rune-alloc/src/vec/mod.rs index d91eddfd3..4adc6d318 100644 --- a/crates/rune-alloc/src/alloc/vec/mod.rs +++ b/crates/rune-alloc/src/vec/mod.rs @@ -84,8 +84,8 @@ use self::is_zero::IsZero; #[cfg(rune_nightly)] mod is_zero; -pub use crate::alloc::slice::into_vec; - +#[cfg(feature = "alloc")] +use core::alloc::Layout; use core::borrow::Borrow; use core::cmp; use core::cmp::Ordering; @@ -97,16 +97,17 @@ use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::slice::{self, SliceIndex}; -#[cfg(test)] -use crate::alloc::testing::*; +use crate::alloc::{Allocator, Global, SizedTypeProperties}; +use crate::clone::TryClone; +use crate::error::Error; +use crate::iter::{TryExtend, TryFromIteratorIn}; use crate::ptr::{self, NonNull}; +use crate::raw_vec::RawVec; use crate::slice::range as slice_range; use crate::slice::{RawIter, RawIterMut}; - -use super::raw_vec::RawVec; -use super::{ - Allocator, Box, Error, Global, SizedTypeProperties, TryClone, TryExtend, TryFromIteratorIn, -}; +#[cfg(test)] +use crate::testing::*; +use crate::Box; /// Construct a vector from an element that can be cloned. #[doc(hidden)] @@ -469,6 +470,26 @@ impl Vec { pub fn try_with_capacity(capacity: usize) -> Result { Self::try_with_capacity_in(capacity, Global) } + + /// Convert a [`Vec`] into a std `Vec`. + /// + /// The result is allocated on the heap, using the default global allocator + /// so this is a zero-copy operation. + /// + /// The memory previously occupied by this vector will be released. + #[cfg(feature = "alloc")] + pub fn into_std(self) -> ::rust_alloc::vec::Vec { + let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc(); + + if let Ok(layout) = Layout::array::(cap) { + alloc.release(layout); + } + + // SAFETY: All the internal invariants of this vector matches what is + // needed to construct a rust vector, and the memory has been allocated + // using the std `Global` allocator. + unsafe { ::rust_alloc::vec::Vec::from_raw_parts(ptr, len, cap) } + } } impl Vec { @@ -479,7 +500,8 @@ impl Vec { /// # Examples /// /// ``` - /// use rune_alloc::{Vec, Global}; + /// use rune_alloc::Vec; + /// use rune_alloc::alloc::Global; /// /// let mut vec: Vec = Vec::new_in(Global); /// ``` @@ -520,7 +542,8 @@ impl Vec { /// # Examples /// /// ``` - /// use rune_alloc::{Vec, Global}; + /// use rune_alloc::Vec; + /// use rune_alloc::alloc::Global; /// /// let mut vec = Vec::try_with_capacity_in(10, Global)?; /// @@ -605,7 +628,8 @@ impl Vec { /// # Examples /// /// ``` - /// use rune_alloc::{Vec, Global}; + /// use rune_alloc::Vec; + /// use rune_alloc::alloc::Global; /// /// use std::ptr; /// use std::mem; @@ -642,7 +666,9 @@ impl Vec { /// /// ```rust /// use core::alloc::Layout; - /// use rune_alloc::{Vec, AllocError, Allocator, Global}; + /// + /// use rune_alloc::Vec; + /// use rune_alloc::alloc::{Allocator, AllocError, Global}; /// /// let layout = Layout::array::(16).expect("overflow cannot happen"); /// @@ -702,7 +728,8 @@ impl Vec { /// # Examples /// /// ``` - /// use rune_alloc::{Vec, Global}; + /// use rune_alloc::Vec; + /// use rune_alloc::alloc::Global; /// /// let mut v: Vec = Vec::new_in(Global); /// v.try_push(-1)?; @@ -737,7 +764,8 @@ impl Vec { /// # Examples /// /// ``` - /// use rune_alloc::{Vec, Global}; + /// use rune_alloc::Vec; + /// use rune_alloc::alloc::Global; /// /// let mut vec: Vec = Vec::try_with_capacity_in(10, Global)?; /// vec.try_push(42)?; @@ -1655,7 +1683,8 @@ impl Vec { /// # Examples /// /// ``` - /// use rune_alloc::{Vec, Global}; + /// use rune_alloc::Vec; + /// use rune_alloc::alloc::Global; /// /// let mut vec: Vec = Vec::try_with_capacity_in(2, Global)?; /// vec.try_push(1)?; @@ -1841,7 +1870,8 @@ impl Vec { /// # Examples /// /// ``` - /// use rune_alloc::{Vec, IteratorExt}; + /// use rune_alloc::Vec; + /// use rune_alloc::prelude::*; /// /// let mut v = rune_alloc::try_vec![1, 2, 3]; /// let u: Vec<_> = v.drain(1..).try_collect()?; @@ -1920,7 +1950,8 @@ impl Vec { /// # Examples /// /// ``` - /// use rune_alloc::{Vec, Global}; + /// use rune_alloc::Vec; + /// use rune_alloc::alloc::Global; /// /// let mut a = Vec::new_in(Global); /// @@ -2510,7 +2541,7 @@ where { fn try_clone(&self) -> Result { let alloc = self.allocator().clone(); - crate::alloc::slice::to_vec(self, alloc) + crate::slice::to_vec(self, alloc) } } @@ -2756,22 +2787,6 @@ impl AsMut<[T]> for Vec { } } -#[cfg(feature = "alloc")] -impl From> for ::rust_alloc::vec::Vec { - /// Try to convert a [`Vec`] into a std `Vec`. - /// - /// The result is allocated on the heap. - fn from(values: Vec) -> Self { - let mut vec = ::rust_alloc::vec::Vec::with_capacity(values.len()); - - for value in values { - vec.push(value); - } - - vec - } -} - impl TryFrom<&[T]> for Vec where T: TryClone, @@ -2833,14 +2848,20 @@ impl TryFrom<::rust_alloc::vec::Vec> for Vec { /// Converts a std `Vec` into a [`Vec`]. /// /// The result is allocated on the heap. - fn try_from(values: ::rust_alloc::vec::Vec) -> Result { - let mut v = Self::try_with_capacity_in(values.len(), Global)?; + fn try_from(vec: ::rust_alloc::vec::Vec) -> Result { + let mut vec = ManuallyDrop::new(vec); - for value in values { - v.try_push(value)?; + let ptr = vec.as_mut_ptr(); + let length = vec.len(); + let capacity = vec.capacity(); + + if let Ok(layout) = Layout::array::(capacity) { + Global.take(layout)?; } - Ok(v) + // SAFETY: The layout of the vector is identical to the std vector and + // it uses the same underlying allocator. + unsafe { Ok(Self::from_raw_parts_in(ptr, length, capacity, Global)) } } } @@ -2860,7 +2881,8 @@ impl TryFrom> for [T; N] { /// /// If the length doesn't match, the input comes back in `Err`: /// ``` - /// use rune_alloc::{Vec, IteratorExt}; + /// use rune_alloc::Vec; + /// use rune_alloc::prelude::*; /// /// let r: Result<[i32; 4], _> = (0..10).try_collect::>()?.try_into(); /// assert_eq!(r, Err(rune_alloc::try_vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); @@ -2899,20 +2921,28 @@ impl TryFrom> for [T; N] { } impl From> for Vec { - /// Convert a boxed slice into a vector by transferring ownership of - /// the existing heap allocation. + /// Convert a boxed slice into a vector by transferring ownership of the + /// existing heap allocation. /// /// # Examples /// /// ``` - /// use rune_alloc::{Vec, Box}; + /// use rune_alloc::{Box, Vec}; + /// use rune_alloc::try_vec; + /// + /// let s: Box<[i32]> = Box::try_from([10, 40, 30])?; + /// let x: Vec = Vec::from(s); + /// + /// assert_eq!(x, [10, 40, 30]); + /// + /// let s: Box<[i32]> = try_vec![10, 40, 30].try_into_boxed_slice()?; + /// let x: Vec = Vec::from(s); /// - /// let b: Box<[i32]> = rune_alloc::try_vec![1, 2, 3].try_into_boxed_slice()?; - /// assert_eq!(Vec::from(b), rune_alloc::try_vec![1, 2, 3]); + /// assert_eq!(x, [10, 40, 30]); /// # Ok::<_, rune_alloc::Error>(()) /// ``` fn from(s: Box<[T], A>) -> Self { - crate::alloc::slice::into_vec(s) + crate::slice::into_vec(s) } } diff --git a/crates/rune-alloc/src/alloc/vec/partial_eq.rs b/crates/rune-alloc/src/vec/partial_eq.rs similarity index 95% rename from crates/rune-alloc/src/alloc/vec/partial_eq.rs rename to crates/rune-alloc/src/vec/partial_eq.rs index 98b614a96..1a28d4b24 100644 --- a/crates/rune-alloc/src/alloc/vec/partial_eq.rs +++ b/crates/rune-alloc/src/vec/partial_eq.rs @@ -18,7 +18,9 @@ macro_rules! __impl_slice_eq1 { } } +#[cfg(feature = "alloc")] __impl_slice_eq1! { [A: Allocator] Vec, ::rust_alloc::vec::Vec } +#[cfg(feature = "alloc")] __impl_slice_eq1! { [A: Allocator] ::rust_alloc::vec::Vec, Vec } __impl_slice_eq1! { [A1: Allocator, A2: Allocator] Vec, Vec } __impl_slice_eq1! { [A: Allocator] Vec, &[U] } diff --git a/crates/rune-alloc/src/alloc/vec/set_len_on_drop.rs b/crates/rune-alloc/src/vec/set_len_on_drop.rs similarity index 100% rename from crates/rune-alloc/src/alloc/vec/set_len_on_drop.rs rename to crates/rune-alloc/src/vec/set_len_on_drop.rs diff --git a/crates/rune-alloc/src/alloc/vec/spec_extend.rs b/crates/rune-alloc/src/vec/spec_extend.rs similarity index 94% rename from crates/rune-alloc/src/alloc/vec/spec_extend.rs rename to crates/rune-alloc/src/vec/spec_extend.rs index 8f1fcd033..e38929e94 100644 --- a/crates/rune-alloc/src/alloc/vec/spec_extend.rs +++ b/crates/rune-alloc/src/vec/spec_extend.rs @@ -1,9 +1,10 @@ #[cfg(rune_nightly)] use core::slice; -use crate::alloc::{Allocator, Error}; +use crate::alloc::Allocator; #[cfg(rune_nightly)] -use crate::alloc::{TryClone, TryCopy}; +use crate::clone::{TryClone, TryCopy}; +use crate::error::Error; #[cfg(rune_nightly)] use super::IntoIter; diff --git a/crates/rune-alloc/src/alloc/vec/spec_from_elem.rs b/crates/rune-alloc/src/vec/spec_from_elem.rs similarity index 95% rename from crates/rune-alloc/src/alloc/vec/spec_from_elem.rs rename to crates/rune-alloc/src/vec/spec_from_elem.rs index d6b572db3..2d6021ffd 100644 --- a/crates/rune-alloc/src/alloc/vec/spec_from_elem.rs +++ b/crates/rune-alloc/src/vec/spec_from_elem.rs @@ -1,9 +1,11 @@ #[cfg(rune_nightly)] use core::ptr; +use crate::alloc::Allocator; +use crate::clone::TryClone; +use crate::error::Error; #[cfg(rune_nightly)] -use crate::alloc::raw_vec::RawVec; -use crate::alloc::{Allocator, Error, TryClone}; +use crate::raw_vec::RawVec; #[cfg(rune_nightly)] use super::IsZero; diff --git a/crates/rune-alloc/src/alloc/vec/splice.rs b/crates/rune-alloc/src/vec/splice.rs similarity index 98% rename from crates/rune-alloc/src/alloc/vec/splice.rs rename to crates/rune-alloc/src/vec/splice.rs index 25d27a8ab..43004aefc 100644 --- a/crates/rune-alloc/src/alloc/vec/splice.rs +++ b/crates/rune-alloc/src/vec/splice.rs @@ -1,7 +1,8 @@ use core::ptr::{self}; use core::slice::{self}; -use crate::alloc::{Allocator, Error}; +use crate::alloc::Allocator; +use crate::error::Error; use super::{Drain, Vec}; diff --git a/crates/rune-alloc/src/alloc/vec_deque/drain.rs b/crates/rune-alloc/src/vec_deque/drain.rs similarity index 100% rename from crates/rune-alloc/src/alloc/vec_deque/drain.rs rename to crates/rune-alloc/src/vec_deque/drain.rs diff --git a/crates/rune-alloc/src/alloc/vec_deque/into_iter.rs b/crates/rune-alloc/src/vec_deque/into_iter.rs similarity index 97% rename from crates/rune-alloc/src/alloc/vec_deque/into_iter.rs rename to crates/rune-alloc/src/vec_deque/into_iter.rs index 9da531aaf..812906666 100644 --- a/crates/rune-alloc/src/alloc/vec_deque/into_iter.rs +++ b/crates/rune-alloc/src/vec_deque/into_iter.rs @@ -2,7 +2,9 @@ use core::fmt; use core::iter::FusedIterator; use core::ptr; -use crate::{Allocator, Error, Global, TryClone}; +use crate::alloc::{Allocator, Global}; +use crate::clone::TryClone; +use crate::error::Error; use super::VecDeque; diff --git a/crates/rune-alloc/src/alloc/vec_deque/iter.rs b/crates/rune-alloc/src/vec_deque/iter.rs similarity index 100% rename from crates/rune-alloc/src/alloc/vec_deque/iter.rs rename to crates/rune-alloc/src/vec_deque/iter.rs diff --git a/crates/rune-alloc/src/alloc/vec_deque/iter_mut.rs b/crates/rune-alloc/src/vec_deque/iter_mut.rs similarity index 100% rename from crates/rune-alloc/src/alloc/vec_deque/iter_mut.rs rename to crates/rune-alloc/src/vec_deque/iter_mut.rs diff --git a/crates/rune-alloc/src/alloc/vec_deque/macros.rs b/crates/rune-alloc/src/vec_deque/macros.rs similarity index 100% rename from crates/rune-alloc/src/alloc/vec_deque/macros.rs rename to crates/rune-alloc/src/vec_deque/macros.rs diff --git a/crates/rune-alloc/src/alloc/vec_deque/mod.rs b/crates/rune-alloc/src/vec_deque/mod.rs similarity index 98% rename from crates/rune-alloc/src/alloc/vec_deque/mod.rs rename to crates/rune-alloc/src/vec_deque/mod.rs index a863806ad..f158cbcba 100644 --- a/crates/rune-alloc/src/alloc/vec_deque/mod.rs +++ b/crates/rune-alloc/src/vec_deque/mod.rs @@ -21,11 +21,13 @@ use core::slice; #[allow(unused_imports)] use core::mem; -use crate::alloc::raw_vec::RawVec; -use crate::alloc::{ - Allocator, Error, Global, SizedTypeProperties, TryClone, TryExtend, TryFromIteratorIn, Vec, -}; +use crate::alloc::{Allocator, Global, SizedTypeProperties}; +use crate::clone::TryClone; +use crate::error::Error; +use crate::iter::{TryExtend, TryFromIteratorIn}; +use crate::raw_vec::RawVec; use crate::slice::range as slice_range; +use crate::vec::Vec; #[macro_use] mod macros; @@ -553,7 +555,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, Global}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::alloc::Global; /// /// let deque: VecDeque = VecDeque::try_with_capacity_in(10, Global)?; /// # Ok::<_, rune_alloc::Error>(()) @@ -736,7 +739,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, Error, TryExtend}; + /// use rune_alloc::{VecDeque, Error}; + /// use rune_alloc::prelude::*; /// /// fn process_data(data: &[u32]) -> Result, Error> { /// let mut output = VecDeque::new(); @@ -784,7 +788,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, Error, TryExtend}; + /// use rune_alloc::{VecDeque, Error}; + /// use rune_alloc::prelude::*; /// /// fn process_data(data: &[u32]) -> Result, Error> { /// let mut output = VecDeque::new(); @@ -826,7 +831,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, TryExtend}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::prelude::*; /// /// let mut buf = VecDeque::try_with_capacity(15)?; /// buf.try_extend(0..4)?; @@ -849,7 +855,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, TryExtend}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::prelude::*; /// /// let mut buf = VecDeque::try_with_capacity(15)?; /// buf.try_extend(0..4)?; @@ -1017,7 +1024,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{Vec, VecDeque, IteratorExt}; + /// use rune_alloc::{Vec, VecDeque}; + /// use rune_alloc::prelude::*; /// /// let mut buf = VecDeque::new(); /// buf.try_push_back(5)?; @@ -1228,7 +1236,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, IteratorExt}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::prelude::*; /// /// let deque: VecDeque<_> = [1, 2, 3].try_into()?; /// let range = deque.range(2..).copied().try_collect::>()?; @@ -1316,7 +1325,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, IteratorExt}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::prelude::*; /// /// let mut deque: VecDeque<_> = [1, 2, 3].try_into()?; /// let drained = deque.drain(2..).try_collect::>()?; @@ -1925,7 +1935,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, TryExtend}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::prelude::*; /// /// let mut buf = VecDeque::new(); /// buf.try_extend(1..5)?; @@ -1938,7 +1949,8 @@ impl VecDeque { /// external state may be used to decide which elements to keep. /// /// ``` - /// use rune_alloc::{VecDeque, TryExtend}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::prelude::*; /// /// let mut buf = VecDeque::new(); /// buf.try_extend(1..6)?; @@ -1965,7 +1977,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, TryExtend}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::prelude::*; /// /// let mut buf = VecDeque::new(); /// buf.try_extend(1..5)?; @@ -2275,7 +2288,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, IteratorExt}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::prelude::*; /// /// let mut buf: VecDeque<_> = (0..10).try_collect()?; /// @@ -2318,7 +2332,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, IteratorExt}; + /// use rune_alloc::VecDeque; + /// use rune_alloc::prelude::*; /// /// let mut buf: VecDeque<_> = (0..10).try_collect()?; /// @@ -2794,7 +2809,8 @@ impl From> for Vec { /// # Examples /// /// ``` - /// use rune_alloc::{VecDeque, Vec, IteratorExt}; + /// use rune_alloc::{VecDeque, Vec}; + /// use rune_alloc::prelude::*; /// /// // This one is *O*(1). /// let deque: VecDeque<_> = (1..5).try_collect()?; diff --git a/crates/rune-alloc/src/alloc/vec_deque/raw_iter.rs b/crates/rune-alloc/src/vec_deque/raw_iter.rs similarity index 100% rename from crates/rune-alloc/src/alloc/vec_deque/raw_iter.rs rename to crates/rune-alloc/src/vec_deque/raw_iter.rs diff --git a/crates/rune-core/Cargo.toml b/crates/rune-core/Cargo.toml index cfdb7d9af..13a72c5db 100644 --- a/crates/rune-core/Cargo.toml +++ b/crates/rune-core/Cargo.toml @@ -16,15 +16,14 @@ categories = ["parser-implementations"] [features] default = ["alloc"] doc = [] -std = ["alloc"] +std = ["alloc", "rune-alloc/std"] alloc = ["serde/alloc", "rune-alloc/alloc"] [dependencies] -rune-alloc = { path = "../rune-alloc", version = "0.12.3" } +rune-alloc = { path = "../rune-alloc", version = "0.12.3", default-features = false, features = ["serde"] } twox-hash = { version = "1.6.3", default-features = false } serde = { version = "1.0.163", default-features = false, features = ["derive"] } -smallvec = { version = "1.10.0", default-features = false, features = ["const_new", "serde"] } byteorder = { version = "1.4.3", default-features = false } musli = { version = "0.0.42", default-features = false, optional = true } diff --git a/crates/rune-core/src/error.rs b/crates/rune-core/src/error.rs index 69d2f309d..9cbd83c6e 100644 --- a/crates/rune-core/src/error.rs +++ b/crates/rune-core/src/error.rs @@ -1,7 +1,7 @@ //! Our own private error trait for use in no-std environments. #[cfg(feature = "alloc")] -use alloc::boxed::Box; +use crate::alloc::boxed::Box; pub trait Error { #[inline] @@ -21,4 +21,4 @@ where } } -impl Error for ::rune_alloc::Error {} +impl Error for crate::alloc::Error {} diff --git a/crates/rune-core/src/hash.rs b/crates/rune-core/src/hash.rs index 6ee0b9b06..65083cdac 100644 --- a/crates/rune-core/src/hash.rs +++ b/crates/rune-core/src/hash.rs @@ -1,4 +1,7 @@ +pub use self::into_hash::IntoHash; mod into_hash; + +pub use self::to_type_hash::ToTypeHash; mod to_type_hash; use core::fmt; @@ -11,8 +14,8 @@ use twox_hash::XxHash64; use crate::protocol::Protocol; -pub use self::into_hash::IntoHash; -pub use self::to_type_hash::ToTypeHash; +use crate::alloc; +use crate::alloc::clone::TryClone; const SEP: u64 = 0x4bc94d6bd06053ad; const PARAMS: u64 = 0x19893cc8f39b1371; @@ -182,6 +185,12 @@ impl Hash { } } +impl TryClone for Hash { + fn try_clone(&self) -> alloc::Result { + Ok(*self) + } +} + impl fmt::Display for Hash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "0x{:x}", self.0) diff --git a/crates/rune-core/src/hash/to_type_hash.rs b/crates/rune-core/src/hash/to_type_hash.rs index 57b2bb155..b66571375 100644 --- a/crates/rune-core/src/hash/to_type_hash.rs +++ b/crates/rune-core/src/hash/to_type_hash.rs @@ -1,5 +1,7 @@ use core::hash::{self, Hash as _, Hasher as _}; +#[cfg(feature = "alloc")] +use crate::alloc::Error; use crate::hash::{Hash, TYPE}; use crate::item::{IntoComponent, ItemBuf}; @@ -14,7 +16,8 @@ pub trait ToTypeHash { /// Optionally convert into an item, if appropriate. #[doc(hidden)] - fn to_item(&self) -> Option; + #[cfg(feature = "alloc")] + fn to_item(&self) -> Result, Error>; /// Hash the current value in-place. #[doc(hidden)] @@ -36,8 +39,9 @@ where } #[inline] - fn to_item(&self) -> Option { - Some(ItemBuf::with_item(*self)) + #[cfg(feature = "alloc")] + fn to_item(&self) -> Result, Error> { + Ok(Some(ItemBuf::with_item(*self)?)) } #[inline] @@ -60,8 +64,9 @@ impl ToTypeHash for Hash { } #[inline] - fn to_item(&self) -> Option { - None + #[cfg(feature = "alloc")] + fn to_item(&self) -> Result, Error> { + Ok(None) } #[inline] diff --git a/crates/rune-core/src/item.rs b/crates/rune-core/src/item.rs index 08d308c47..05fb5f416 100644 --- a/crates/rune-core/src/item.rs +++ b/crates/rune-core/src/item.rs @@ -1,4 +1,6 @@ +#[cfg(feature = "alloc")] mod item_buf; +#[cfg(feature = "alloc")] pub use self::item_buf::ItemBuf; mod item; @@ -20,5 +22,7 @@ pub use self::into_component::IntoComponent; mod internal; +mod serde; + #[cfg(test)] mod tests; diff --git a/crates/rune-core/src/item/component.rs b/crates/rune-core/src/item/component.rs index bb58d07ba..09abf4a4c 100644 --- a/crates/rune-core/src/item/component.rs +++ b/crates/rune-core/src/item/component.rs @@ -1,20 +1,20 @@ use core::fmt; -use alloc::boxed::Box; +use crate::alloc::Box; use serde::{Deserialize, Serialize}; +use crate::alloc; +use crate::alloc::clone::TryClone; use crate::item::ComponentRef; -#[cfg(feature = "alloc")] -use rune_alloc::{Error, TryClone}; - /// The component of an item. /// /// All indexes refer to sibling indexes. So two sibling id components could /// have the indexes `1` and `2` respectively. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[non_exhaustive] +#[serde(rename_all = "snake_case", tag = "type")] pub enum Component { /// A crate component. Crate(Box), @@ -43,6 +43,16 @@ impl Component { } } +impl TryClone for Component { + fn try_clone(&self) -> alloc::Result { + Ok(match self { + Component::Crate(string) => Component::Crate(string.try_clone()?), + Component::Str(string) => Component::Str(string.try_clone()?), + Component::Id(id) => Component::Id(*id), + }) + } +} + impl fmt::Display for Component { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -52,12 +62,3 @@ impl fmt::Display for Component { } } } - -#[cfg(feature = "alloc")] -impl TryClone for Component { - #[inline] - fn try_clone(&self) -> Result { - // TODO: use fallible allocations for component. - Ok(self.clone()) - } -} diff --git a/crates/rune-core/src/item/component_ref.rs b/crates/rune-core/src/item/component_ref.rs index bb0be3785..fc4e9a477 100644 --- a/crates/rune-core/src/item/component_ref.rs +++ b/crates/rune-core/src/item/component_ref.rs @@ -2,6 +2,8 @@ use core::fmt; use serde::{Deserialize, Serialize}; +#[cfg(feature = "alloc")] +use crate::alloc::Error; #[cfg(feature = "alloc")] use crate::item::Component; @@ -40,12 +42,12 @@ impl<'a> ComponentRef<'a> { /// Coerce this [ComponentRef] into an owned [Component]. #[cfg(feature = "alloc")] - pub fn to_owned(&self) -> Component { - match *self { - ComponentRef::Crate(s) => Component::Crate(s.into()), - ComponentRef::Str(s) => Component::Str(s.into()), + pub fn to_owned(&self) -> Result { + Ok(match *self { + ComponentRef::Crate(s) => Component::Crate(s.try_into()?), + ComponentRef::Str(s) => Component::Str(s.try_into()?), ComponentRef::Id(id) => Component::Id(id), - } + }) } } diff --git a/crates/rune-core/src/item/internal.rs b/crates/rune-core/src/item/internal.rs index ac745cdbf..1fe2a133e 100644 --- a/crates/rune-core/src/item/internal.rs +++ b/crates/rune-core/src/item/internal.rs @@ -2,15 +2,15 @@ use core::hash::{self, Hash}; use core::str; use byteorder::{ByteOrder, NativeEndian}; -use smallvec::SmallVec; + +use crate::alloc::alloc::Allocator; +use crate::alloc::{self, Vec}; // Types available. pub(super) const CRATE: Tag = Tag(0b00); pub(super) const STRING: Tag = Tag(0b01); pub(super) const ID: Tag = Tag(0b10); -/// Inline size. -pub(super) const INLINE: usize = 32; /// How many bits the type of a tag takes up. pub(super) const TYPE_BITS: usize = 2; /// Mask of the type of a tag. @@ -40,7 +40,11 @@ pub(super) fn read_tag(content: &[u8]) -> (Tag, usize) { /// # Panics /// /// Panics if the provided size cannot fit withing an identifier. -pub(super) fn write_tag(output: &mut SmallVec<[u8; INLINE]>, Tag(tag): Tag, n: usize) { +pub(super) fn write_tag( + output: &mut Vec, + Tag(tag): Tag, + n: usize, +) -> alloc::Result<()> { let tag = usize::try_from(tag).expect("tag out of bounds"); debug_assert!(tag <= TYPE_MASK); assert!( @@ -50,21 +54,24 @@ pub(super) fn write_tag(output: &mut SmallVec<[u8; INLINE]>, Tag(tag): Tag, n: u let n = u16::try_from(n << TYPE_BITS | tag).expect("tag out of bounds"); let mut buf = [0, 0]; NativeEndian::write_u16(&mut buf[..], n); - output.extend_from_slice(&buf[..]); + output.try_extend_from_slice(&buf[..])?; + Ok(()) } /// Internal function to write only the crate of a component. -pub(super) fn write_crate(s: &str, output: &mut SmallVec<[u8; INLINE]>) { - write_tag(output, CRATE, s.len()); - output.extend_from_slice(s.as_bytes()); - write_tag(output, CRATE, s.len()); +pub(super) fn write_crate(s: &str, output: &mut Vec) -> alloc::Result<()> { + write_tag(output, CRATE, s.len())?; + output.try_extend_from_slice(s.as_bytes())?; + write_tag(output, CRATE, s.len())?; + Ok(()) } /// Internal function to write only the string of a component. -pub(super) fn write_str(s: &str, output: &mut SmallVec<[u8; INLINE]>) { - write_tag(output, STRING, s.len()); - output.extend_from_slice(s.as_bytes()); - write_tag(output, STRING, s.len()); +pub(super) fn write_str(s: &str, output: &mut Vec) -> alloc::Result<()> { + write_tag(output, STRING, s.len())?; + output.try_extend_from_slice(s.as_bytes())?; + write_tag(output, STRING, s.len())?; + Ok(()) } /// Internal function to hash the given string. diff --git a/crates/rune-core/src/item/into_component.rs b/crates/rune-core/src/item/into_component.rs index eda4e2707..edb12ec38 100644 --- a/crates/rune-core/src/item/into_component.rs +++ b/crates/rune-core/src/item/into_component.rs @@ -1,13 +1,13 @@ use core::hash::{self, Hash}; #[cfg(feature = "alloc")] -use alloc::borrow::Cow; +use crate::alloc::alloc::Allocator; #[cfg(feature = "alloc")] -use alloc::boxed::Box; +use crate::alloc::borrow::Cow; #[cfg(feature = "alloc")] -use alloc::string::String; - -use smallvec::SmallVec; +use crate::alloc::clone::TryClone; +#[cfg(feature = "alloc")] +use crate::alloc::{Box, Error, String, Vec}; #[cfg(feature = "alloc")] use crate::item::Component; @@ -22,14 +22,15 @@ pub trait IntoComponent: Sized { /// Convert into component. #[inline] #[cfg(feature = "alloc")] - fn into_component(self) -> Component { + fn into_component(self) -> Result { into_component(self.as_component_ref()) } /// Write a component directly to a buffer. #[inline] #[doc(hidden)] - fn write_component(self, output: &mut SmallVec<[u8; internal::INLINE]>) { + #[cfg(feature = "alloc")] + fn write_component(self, output: &mut Vec) -> Result<(), Error> { write_component(self.as_component_ref(), output) } @@ -52,7 +53,7 @@ impl IntoComponent for ComponentRef<'_> { #[inline] #[cfg(feature = "alloc")] - fn into_component(self) -> Component { + fn into_component(self) -> Result { into_component(self) } } @@ -65,7 +66,7 @@ impl IntoComponent for &ComponentRef<'_> { #[inline] #[cfg(feature = "alloc")] - fn into_component(self) -> Component { + fn into_component(self) -> Result { into_component(*self) } } @@ -78,8 +79,8 @@ impl IntoComponent for Component { } #[inline] - fn into_component(self) -> Component { - self + fn into_component(self) -> Result { + Ok(self) } } @@ -91,8 +92,8 @@ impl IntoComponent for &Component { } #[inline] - fn into_component(self) -> Component { - self.clone() + fn into_component(self) -> Result { + self.try_clone() } } @@ -104,11 +105,12 @@ macro_rules! impl_into_component_for_str { } #[cfg(feature = "alloc")] - fn into_component($slf) -> Component { - Component::Str($into) + fn into_component($slf) -> Result { + Ok(Component::Str($into)) } - fn write_component(self, output: &mut smallvec::SmallVec<[u8; internal::INLINE]>) { + #[cfg(feature = "alloc")] + fn write_component(self, output: &mut Vec) -> Result<(), Error> { internal::write_str(self.as_ref(), output) } @@ -122,43 +124,47 @@ macro_rules! impl_into_component_for_str { } } -impl_into_component_for_str!(&str, self, self.into()); -impl_into_component_for_str!(&&str, self, (*self).into()); -impl_into_component_for_str!(RawStr, self, (*self).into()); -impl_into_component_for_str!(&RawStr, self, (**self).into()); +impl_into_component_for_str!(&str, self, self.try_into()?); +impl_into_component_for_str!(&&str, self, (*self).try_into()?); +impl_into_component_for_str!(RawStr, self, (*self).try_into()?); +impl_into_component_for_str!(&RawStr, self, (**self).try_into()?); #[cfg(feature = "alloc")] -impl_into_component_for_str!(String, self, self.into()); +impl_into_component_for_str!(String, self, self.as_str().try_into()?); #[cfg(feature = "alloc")] -impl_into_component_for_str!(&String, self, self.clone().into()); +impl_into_component_for_str!(&String, self, self.as_str().try_into()?); #[cfg(feature = "alloc")] impl_into_component_for_str!(Box, self, self); #[cfg(feature = "alloc")] -impl_into_component_for_str!(&Box, self, self.clone()); +impl_into_component_for_str!(&Box, self, self.try_clone()?); #[cfg(feature = "alloc")] -impl_into_component_for_str!(Cow<'_, str>, self, self.as_ref().into()); +impl_into_component_for_str!(Cow<'_, str>, self, self.as_ref().try_into()?); +#[cfg(feature = "alloc")] +impl_into_component_for_str!( + ::rust_alloc::borrow::Cow<'_, str>, + self, + self.as_ref().try_into()? +); /// Convert into an owned component. #[cfg(feature = "alloc")] -fn into_component(component: ComponentRef<'_>) -> Component { - match component { - ComponentRef::Crate(s) => Component::Crate(s.into()), - ComponentRef::Str(s) => Component::Str(s.into()), +fn into_component(component: ComponentRef<'_>) -> Result { + Ok(match component { + ComponentRef::Crate(s) => Component::Crate(s.try_into()?), + ComponentRef::Str(s) => Component::Str(s.try_into()?), ComponentRef::Id(n) => Component::Id(n), - } + }) } /// Write the current component to the given vector. -fn write_component(component: ComponentRef<'_>, output: &mut SmallVec<[u8; internal::INLINE]>) { +#[cfg(feature = "alloc")] +fn write_component( + component: ComponentRef<'_>, + output: &mut Vec, +) -> Result<(), Error> { match component { - ComponentRef::Crate(s) => { - internal::write_crate(s, output); - } - ComponentRef::Str(s) => { - internal::write_str(s, output); - } - ComponentRef::Id(c) => { - internal::write_tag(output, internal::ID, c); - } + ComponentRef::Crate(s) => internal::write_crate(s, output), + ComponentRef::Str(s) => internal::write_str(s, output), + ComponentRef::Id(c) => internal::write_tag(output, internal::ID, c), } } diff --git a/crates/rune-core/src/item/item.rs b/crates/rune-core/src/item/item.rs index eb704dd39..14838e979 100644 --- a/crates/rune-core/src/item/item.rs +++ b/crates/rune-core/src/item/item.rs @@ -1,11 +1,11 @@ use core::fmt; #[cfg(feature = "alloc")] -use alloc::borrow::ToOwned; +use crate::alloc::borrow::TryToOwned; #[cfg(feature = "alloc")] -use alloc::vec::Vec; - -use smallvec::ToSmallVec; +use crate::alloc::iter::IteratorExt; +#[cfg(feature = "alloc")] +use crate::alloc::{Error, Vec}; #[cfg(feature = "alloc")] use crate::item::Component; @@ -116,10 +116,10 @@ impl Item { /// Construct a new vector from the current item. #[cfg(feature = "alloc")] - pub fn as_vec(&self) -> Vec { + pub fn as_vec(&self) -> Result, Error> { self.iter() .map(ComponentRef::into_component) - .collect::>() + .try_collect::, _>>()? } /// If the item only contains one element, return that element. @@ -132,34 +132,61 @@ impl Item { } } - /// Join this path with another. - pub fn join(&self, other: I) -> ItemBuf + /// Return an owned and joined variant of this item. + /// + /// # Examples + /// + /// ``` + /// use rune::compile::{Item, ComponentRef}; + /// + /// let item = Item::new(); + /// assert!(item.is_empty()); + /// + /// let item2 = item.join(["hello", "world"])?; + /// assert_eq!(item2.first(), Some(ComponentRef::Str("hello"))); + /// assert_eq!(item2.last(), Some(ComponentRef::Str("world"))); + /// # Ok::<(), rune::support::Error>(()) + /// ``` + pub fn join(&self, other: I) -> Result where I: IntoIterator, I::Item: IntoComponent, { - let mut content = self.content.to_smallvec(); + let mut content = self.content.try_to_owned()?; for c in other { - c.write_component(&mut content); + c.write_component(&mut content)?; } // SAFETY: construction through write_component ensures valid // construction of buffer. - unsafe { ItemBuf::from_raw(content) } + Ok(unsafe { ItemBuf::from_raw(content) }) } - /// Clone and extend the item path. - pub fn extended(&self, part: C) -> ItemBuf + /// Return an owned and extended variant of this item. + /// + /// # Examples + /// + /// ``` + /// use rune::compile::{Item, ComponentRef}; + /// + /// let item = Item::new(); + /// assert!(item.is_empty()); + /// + /// let item2 = item.extended("hello")?; + /// assert_eq!(item2.first(), Some(ComponentRef::Str("hello"))); + /// # Ok::<(), rune::support::Error>(()) + /// ``` + pub fn extended(&self, part: C) -> Result where C: IntoComponent, { - let mut content = self.content.to_smallvec(); - part.write_component(&mut content); + let mut content = self.content.try_to_owned()?; + part.write_component(&mut content)?; // SAFETY: construction through write_component ensures valid // construction of buffer. - unsafe { ItemBuf::from_raw(content) } + Ok(unsafe { ItemBuf::from_raw(content) }) } /// Access the last component in the path. @@ -177,12 +204,12 @@ impl Item { /// /// let mut item = ItemBuf::new(); /// - /// item.push("start"); - /// item.push(ComponentRef::Id(1)); - /// item.push(ComponentRef::Id(2)); - /// item.push("middle"); - /// item.push(ComponentRef::Id(3)); - /// item.push("end"); + /// item.push("start")?; + /// item.push(ComponentRef::Id(1))?; + /// item.push(ComponentRef::Id(2))?; + /// item.push("middle")?; + /// item.push(ComponentRef::Id(3))?; + /// item.push("end")?; /// /// let mut it = item.iter(); /// @@ -195,6 +222,7 @@ impl Item { /// assert_eq!(it.next(), None); /// /// assert!(!item.is_empty()); + /// # Ok::<(), rune::support::Error>(()) /// ``` #[inline] pub fn iter(&self) -> Iter<'_> { @@ -277,7 +305,7 @@ impl Item { /// ItemBuf::with_item(["a", "b", "c"]).ancestry(&ItemBuf::with_item(["a", "b", "d", "e"])) /// ); /// ``` - pub fn ancestry(&self, other: &Self) -> (ItemBuf, ItemBuf) { + pub fn ancestry(&self, other: &Self) -> Result<(ItemBuf, ItemBuf), Error> { let mut a = self.iter(); let mut b = other.iter(); @@ -287,21 +315,21 @@ impl Item { while let Some(v) = b.next() { if let Some(u) = a.next() { if u == v { - shared.push(v); + shared.push(v)?; continue; } else { - suffix.push(v); - suffix.extend(b); - return (shared, suffix); + suffix.push(v)?; + suffix.extend(b)?; + return Ok((shared, suffix)); } } - suffix.push(v); + suffix.push(v)?; break; } - suffix.extend(b); - (shared, suffix) + suffix.extend(b)?; + Ok((shared, suffix)) } /// Get the parent item for the current item. @@ -338,13 +366,13 @@ impl Default for &Item { } #[cfg(feature = "alloc")] -impl ToOwned for Item { +impl TryToOwned for Item { type Owned = ItemBuf; #[inline] - fn to_owned(&self) -> Self::Owned { + fn try_to_owned(&self) -> Result { // SAFETY: item ensures that content is valid. - unsafe { ItemBuf::from_raw(self.content.to_smallvec()) } + Ok(unsafe { ItemBuf::from_raw(self.content.try_to_owned()?) }) } } diff --git a/crates/rune-core/src/item/item_buf.rs b/crates/rune-core/src/item/item_buf.rs index 401766f79..5b47c6515 100644 --- a/crates/rune-core/src/item/item_buf.rs +++ b/crates/rune-core/src/item/item_buf.rs @@ -1,20 +1,18 @@ use core::borrow::Borrow; +use core::cmp::Ordering; use core::fmt; -use core::hash::Hash; +use core::hash::{Hash, Hasher}; use core::mem::take; use core::ops::Deref; use core::str::FromStr; use crate::error; -#[cfg(feature = "alloc")] -use alloc::vec::{self, Vec}; +use crate::alloc::alloc::{Allocator, Global}; +use crate::alloc::clone::TryClone; +use crate::alloc::iter::TryFromIteratorIn; +use crate::alloc::{self, Vec}; -use serde::{Deserialize, Serialize}; -use smallvec::SmallVec; - -use crate::item::internal::INLINE; -#[cfg(feature = "alloc")] use crate::item::Component; use crate::item::{ComponentRef, IntoComponent, Item, Iter}; @@ -66,10 +64,91 @@ use crate::item::{ComponentRef, IntoComponent, Item, Iter}; /// ```text /// dddddddd ddddddtt /// ``` -#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[repr(transparent)] -pub struct ItemBuf { - content: SmallVec<[u8; INLINE]>, +pub struct ItemBuf { + content: Vec, +} + +impl ItemBuf { + /// Construct a new item buffer inside of the given allocator. + pub(crate) fn new_in(alloc: A) -> Self { + Self { + content: Vec::new_in(alloc), + } + } + + /// Internal raw constructor for an item. + /// + /// # Safety + /// + /// Caller must ensure that its representation is valid. + pub(super) const unsafe fn from_raw(content: Vec) -> Self { + Self { content } + } + + /// Construct a new item with the given path in the given allocator. + pub(crate) fn with_item_in(iter: I, alloc: A) -> alloc::Result + where + I: IntoIterator, + I::Item: IntoComponent, + { + let mut content = Vec::new_in(alloc); + + for c in iter { + c.write_component(&mut content)?; + } + + Ok(Self { content }) + } + + /// Push the given component to the current item. + pub fn push(&mut self, c: C) -> alloc::Result<()> + where + C: IntoComponent, + { + c.write_component(&mut self.content)?; + Ok(()) + } + + /// Push the given component to the current item. + pub fn pop(&mut self) -> alloc::Result> { + let mut it = self.iter(); + + let Some(c) = it.next_back() else { + return Ok(None); + }; + + let c = c.to_owned()?; + let new_len = it.len(); + + // SAFETY: Advancing the back end of the iterator ensures that the new + // length is smaller than the original, and an item buffer is a byte + // array which does not need to be dropped. + unsafe { + debug_assert!(new_len < self.content.len()); + self.content.set_len(new_len); + } + + Ok(Some(c)) + } + + /// Extend the current item with an iterator. + pub fn extend(&mut self, i: I) -> alloc::Result<()> + where + I: IntoIterator, + I::Item: IntoComponent, + { + for c in i { + self.push(c)?; + } + + Ok(()) + } + + /// Clear the current item. + pub fn clear(&mut self) { + self.content.clear(); + } } impl ItemBuf { @@ -87,19 +166,10 @@ impl ItemBuf { /// ``` pub const fn new() -> Self { Self { - content: SmallVec::new_const(), + content: Vec::new(), } } - /// Internal raw constructor for an item. - /// - /// # Safety - /// - /// Caller must ensure that its representation is valid. - pub(super) const unsafe fn from_raw(content: SmallVec<[u8; INLINE]>) -> Self { - Self { content } - } - /// Construct a new item with the given path. /// /// # Examples @@ -107,25 +177,20 @@ impl ItemBuf { /// ``` /// use rune::compile::{ComponentRef, ItemBuf}; /// - /// let item = ItemBuf::with_item(["foo", "bar"]); + /// let item = ItemBuf::with_item(["foo", "bar"])?; /// let mut it = item.iter(); /// /// assert_eq!(it.next(), Some(ComponentRef::Str("foo"))); /// assert_eq!(it.next(), Some(ComponentRef::Str("bar"))); /// assert_eq!(it.next(), None); + /// # Ok::<(), rune::support::Error>(()) /// ``` - pub fn with_item(iter: I) -> Self + pub fn with_item(iter: I) -> alloc::Result where I: IntoIterator, I::Item: IntoComponent, { - let mut content = SmallVec::new(); - - for c in iter { - c.write_component(&mut content); - } - - Self { content } + Self::with_item_in(iter, Global) } /// Construct item for a crate. @@ -135,7 +200,7 @@ impl ItemBuf { /// ``` /// use rune::compile::{ComponentRef, ItemBuf}; /// - /// let mut item = ItemBuf::with_crate("std"); + /// let mut item = ItemBuf::with_crate("std")?; /// item.push("foo"); /// assert_eq!(item.as_crate(), Some("std")); /// @@ -143,8 +208,9 @@ impl ItemBuf { /// assert_eq!(it.next(), Some(ComponentRef::Crate("std"))); /// assert_eq!(it.next(), Some(ComponentRef::Str("foo"))); /// assert_eq!(it.next(), None); + /// # Ok::<(), rune::support::Error>(()) /// ``` - pub fn with_crate(name: &str) -> Self { + pub fn with_crate(name: &str) -> alloc::Result { Self::with_item(&[ComponentRef::Crate(name)]) } @@ -155,95 +221,103 @@ impl ItemBuf { /// ``` /// use rune::compile::{ComponentRef, ItemBuf}; /// - /// let item = ItemBuf::with_crate_item("std", ["option"]); + /// let item = ItemBuf::with_crate_item("std", ["option"])?; /// assert_eq!(item.as_crate(), Some("std")); /// /// let mut it = item.iter(); /// assert_eq!(it.next(), Some(ComponentRef::Crate("std"))); /// assert_eq!(it.next(), Some(ComponentRef::Str("option"))); /// assert_eq!(it.next(), None); + /// # Ok::<(), rune::support::Error>(()) /// ``` - pub fn with_crate_item(name: &str, iter: I) -> Self + pub fn with_crate_item(name: &str, iter: I) -> alloc::Result where I: IntoIterator, I::Item: IntoComponent, { - let mut content = SmallVec::new(); - ComponentRef::Crate(name).write_component(&mut content); + let mut content = Vec::new(); + ComponentRef::Crate(name).write_component(&mut content)?; for c in iter { - c.write_component(&mut content); + c.write_component(&mut content)?; } - Self { content } + Ok(Self { content }) } +} - /// Push the given component to the current item. - pub fn push(&mut self, c: C) - where - C: IntoComponent, - { - c.write_component(&mut self.content); +impl Default for ItemBuf +where + A: Default, +{ + fn default() -> Self { + Self { + content: Vec::new_in(A::default()), + } } +} - /// Push the given component to the current item. - #[cfg(feature = "alloc")] - pub fn pop(&mut self) -> Option { - let mut it = self.iter(); - let c = it.next_back()?.to_owned(); - let new_len = it.len(); - self.content.resize(new_len, 0); - Some(c) +impl PartialEq for ItemBuf { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.content == other.content } +} - /// Extend the current item with an iterator. - pub fn extend(&mut self, i: I) - where - I: IntoIterator, - I::Item: IntoComponent, - { - for c in i { - self.push(c); - } +impl Eq for ItemBuf {} + +impl PartialOrd for ItemBuf { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.content.cmp(&other.content)) } +} - /// Clear the current item. - pub fn clear(&mut self) { - self.content.clear(); +impl Ord for ItemBuf { + fn cmp(&self, other: &Self) -> Ordering { + self.content.cmp(&other.content) } +} - /// Convert into a vector from the current item. - #[cfg(feature = "alloc")] - pub fn into_vec(self) -> Vec { - self.into_iter().collect::>() +impl Hash for ItemBuf { + fn hash(&self, state: &mut H) { + self.content.hash(state); } } -impl AsRef for ItemBuf { +impl TryClone for ItemBuf { + #[inline] + fn try_clone(&self) -> alloc::Result { + Ok(Self { + content: self.content.try_clone()?, + }) + } +} + +impl AsRef for ItemBuf { #[inline] fn as_ref(&self) -> &Item { self } } -impl Borrow for ItemBuf { +impl Borrow for ItemBuf { #[inline] fn borrow(&self) -> &Item { self } } -impl FromIterator for ItemBuf +impl TryFromIteratorIn for ItemBuf where C: IntoComponent, { #[inline] - fn from_iter>(iter: T) -> Self { - Self::with_item(iter) + fn try_from_iter_in>(iter: T, alloc: A) -> alloc::Result { + Self::with_item_in(iter, alloc) } } -impl Deref for ItemBuf { +impl Deref for ItemBuf { type Target = Item; fn deref(&self) -> &Self::Target { @@ -253,30 +327,19 @@ impl Deref for ItemBuf { } /// Format implementation for an [ItemBuf], defers to [Item]. -impl fmt::Display for ItemBuf { +impl fmt::Display for ItemBuf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Item::fmt(self, f) } } -impl fmt::Debug for ItemBuf { +impl fmt::Debug for ItemBuf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Item::fmt(self, f) } } -#[cfg(feature = "alloc")] -impl IntoIterator for ItemBuf { - type IntoIter = vec::IntoIter; - type Item = Component; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.as_vec().into_iter() - } -} - -impl<'a> IntoIterator for &'a ItemBuf { +impl<'a, A: Allocator> IntoIterator for &'a ItemBuf { type IntoIter = Iter<'a>; type Item = ComponentRef<'a>; @@ -285,31 +348,31 @@ impl<'a> IntoIterator for &'a ItemBuf { } } -impl PartialEq for ItemBuf { +impl PartialEq for ItemBuf { fn eq(&self, other: &Item) -> bool { - self.content.as_ref() == other.as_bytes() + self.content.as_slice() == other.as_bytes() } } -impl PartialEq for &ItemBuf { +impl PartialEq for &ItemBuf { fn eq(&self, other: &Item) -> bool { - self.content.as_ref() == other.as_bytes() + self.content.as_slice() == other.as_bytes() } } -impl PartialEq<&Item> for ItemBuf { +impl PartialEq<&Item> for ItemBuf { fn eq(&self, other: &&Item) -> bool { - self.content.as_ref() == other.as_bytes() + self.content.as_slice() == other.as_bytes() } } -impl PartialEq> for ItemBuf { +impl PartialEq> for ItemBuf { fn eq(&self, other: &Iter<'_>) -> bool { self == other.as_item() } } -impl PartialEq> for &ItemBuf { +impl PartialEq> for &ItemBuf { fn eq(&self, other: &Iter<'_>) -> bool { *self == other.as_item() } @@ -318,22 +381,52 @@ impl PartialEq> for &ItemBuf { /// Error when parsing an item. #[derive(Debug)] #[non_exhaustive] -pub struct FromStrError; +pub struct FromStrError { + kind: FromStrErrorKind, +} + +impl From for FromStrError { + fn from(error: alloc::Error) -> Self { + Self { + kind: FromStrErrorKind::AllocError(error), + } + } +} + +impl From for FromStrError { + fn from(kind: FromStrErrorKind) -> Self { + Self { kind } + } +} + +#[derive(Debug)] +enum FromStrErrorKind { + /// Error during parse. + ParseError, + /// An error occured when allocating. + AllocError(alloc::Error), +} impl fmt::Display for FromStrError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "String is not a valid item") + match &self.kind { + FromStrErrorKind::ParseError => write!(f, "String is not a valid item"), + FromStrErrorKind::AllocError(error) => error.fmt(f), + } } } impl error::Error for FromStrError {} -impl FromStr for ItemBuf { +impl FromStr for ItemBuf +where + A: Default, +{ type Err = FromStrError; fn from_str(s: &str) -> Result { - let mut item = ItemBuf::new(); + let mut item = ItemBuf::new_in(A::default()); let (s, mut next_crate) = if let Some(remainder) = s.strip_prefix("::") { (remainder, true) @@ -343,11 +436,13 @@ impl FromStr for ItemBuf { for c in s.split("::") { if take(&mut next_crate) { - item.push(ComponentRef::Crate(c)); + item.push(ComponentRef::Crate(c))?; } else if let Some(num) = c.strip_prefix('$') { - item.push(ComponentRef::Id(num.parse().map_err(|_| FromStrError)?)); + item.push(ComponentRef::Id( + num.parse().map_err(|_| FromStrErrorKind::ParseError)?, + ))?; } else { - item.push(ComponentRef::Str(c)); + item.push(ComponentRef::Str(c))?; } } diff --git a/crates/rune-core/src/item/serde.rs b/crates/rune-core/src/item/serde.rs new file mode 100644 index 000000000..80acde9f1 --- /dev/null +++ b/crates/rune-core/src/item/serde.rs @@ -0,0 +1,70 @@ +use core::fmt; +use core::marker::PhantomData; + +use serde::de::{self, Error as _}; +use serde::ser::{self, SerializeSeq}; + +use crate::alloc::alloc::Allocator; +use crate::item::{Component, Item, ItemBuf}; + +impl ser::Serialize for Item { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut seq = serializer.serialize_seq(None)?; + + for item in self.iter() { + seq.serialize_element(&item)?; + } + + seq.end() + } +} + +impl ser::Serialize for ItemBuf { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.as_ref().serialize(serializer) + } +} + +impl<'de, A: Allocator> de::Deserialize<'de> for ItemBuf +where + A: Default, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_bytes(BytesVisitor(PhantomData)) + } +} + +struct BytesVisitor(PhantomData); + +impl<'de, A: Allocator> de::Visitor<'de> for BytesVisitor +where + A: Default, +{ + type Value = ItemBuf; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "item buffer deserialization to be implemented") + } + + fn visit_seq(self, mut seq: S) -> Result + where + S: de::SeqAccess<'de>, + { + let mut buf = ItemBuf::new_in(A::default()); + + while let Some(c) = seq.next_element::()? { + buf.push(c).map_err(S::Error::custom)?; + } + + Ok(buf) + } +} diff --git a/crates/rune-core/src/item/tests.rs b/crates/rune-core/src/item/tests.rs index 72e5744b4..15211a09f 100644 --- a/crates/rune-core/src/item/tests.rs +++ b/crates/rune-core/src/item/tests.rs @@ -1,39 +1,41 @@ use crate::item::internal::MAX_DATA; use crate::item::{Component, ComponentRef, IntoComponent, ItemBuf}; +use rune_alloc as alloc; #[test] -fn test_pop() { +fn test_pop() -> alloc::Result<()> { let mut item = ItemBuf::new(); - item.push("start"); - item.push(ComponentRef::Id(1)); - item.push(ComponentRef::Id(2)); - item.push("middle"); - item.push(ComponentRef::Id(3)); - item.push("end"); - - assert_eq!(item.pop(), Some("end".into_component())); - assert_eq!(item.pop(), Some(Component::Id(3))); - assert_eq!(item.pop(), Some("middle".into_component())); - assert_eq!(item.pop(), Some(Component::Id(2))); - assert_eq!(item.pop(), Some(Component::Id(1))); - assert_eq!(item.pop(), Some("start".into_component())); - assert_eq!(item.pop(), None); + item.push("start")?; + item.push(ComponentRef::Id(1))?; + item.push(ComponentRef::Id(2))?; + item.push("middle")?; + item.push(ComponentRef::Id(3))?; + item.push("end")?; + + assert_eq!(item.pop()?, Some("end".into_component()?)); + assert_eq!(item.pop()?, Some(Component::Id(3))); + assert_eq!(item.pop()?, Some("middle".into_component()?)); + assert_eq!(item.pop()?, Some(Component::Id(2))); + assert_eq!(item.pop()?, Some(Component::Id(1))); + assert_eq!(item.pop()?, Some("start".into_component()?)); + assert_eq!(item.pop()?, None); assert!(item.is_empty()); + Ok(()) } #[test] -fn test_next_back_str() { +fn test_next_back_str() -> alloc::Result<()> { let mut item = ItemBuf::new(); - item.push(ComponentRef::Crate("std")); - item.push("start"); - item.push(ComponentRef::Id(1)); - item.push(ComponentRef::Id(2)); - item.push("middle"); - item.push(ComponentRef::Id(3)); - item.push("end"); + item.push(ComponentRef::Crate("std"))?; + item.push("start")?; + item.push(ComponentRef::Id(1))?; + item.push(ComponentRef::Id(2))?; + item.push("middle")?; + item.push(ComponentRef::Id(3))?; + item.push("end")?; let mut it = item.iter(); @@ -45,19 +47,20 @@ fn test_next_back_str() { assert_eq!(it.next_back_str(), Some("start")); assert_eq!(it.next_back(), Some(ComponentRef::Crate("std"))); assert_eq!(it.next_back(), None); + Ok(()) } #[test] -fn alternate() { +fn alternate() -> alloc::Result<()> { let mut item = ItemBuf::new(); - item.push(ComponentRef::Crate("std")); - item.push("start"); - item.push(ComponentRef::Id(1)); - item.push(ComponentRef::Id(2)); - item.push("middle"); - item.push(ComponentRef::Id(3)); - item.push("end"); + item.push(ComponentRef::Crate("std"))?; + item.push("start")?; + item.push(ComponentRef::Id(1))?; + item.push(ComponentRef::Id(2))?; + item.push("middle")?; + item.push(ComponentRef::Id(3))?; + item.push("end")?; let mut it = item.iter(); @@ -70,28 +73,31 @@ fn alternate() { assert_eq!(it.next_str(), Some("middle")); assert_eq!(it.next_back(), None); assert_eq!(it.next(), None); + Ok(()) } #[test] -fn store_max_data() { +fn store_max_data() -> alloc::Result<()> { let mut item = ItemBuf::new(); - item.push(ComponentRef::Id(MAX_DATA - 1)); + item.push(ComponentRef::Id(MAX_DATA - 1))?; assert_eq!(item.last(), Some(ComponentRef::Id(MAX_DATA - 1))); + Ok(()) } #[test] -fn store_max_string() { +fn store_max_string() -> alloc::Result<()> { let mut item = ItemBuf::new(); let s = "x".repeat(MAX_DATA - 1); - item.push(ComponentRef::Str(&s)); + item.push(ComponentRef::Str(&s))?; assert_eq!(item.last(), Some(ComponentRef::Str(&s))); + Ok(()) } #[test] #[should_panic(expected = "item data overflow, index or string size larger than MAX_DATA")] fn store_max_data_overflow() { let mut item = ItemBuf::new(); - item.push(ComponentRef::Id(MAX_DATA)); + item.push(ComponentRef::Id(MAX_DATA)).unwrap(); assert_eq!(item.last(), Some(ComponentRef::Id(MAX_DATA))); } @@ -100,5 +106,5 @@ fn store_max_data_overflow() { fn store_max_string_overflow() { let mut item = ItemBuf::new(); let s = "x".repeat(MAX_DATA); - item.push(ComponentRef::Str(&s)); + item.push(ComponentRef::Str(&s)).unwrap(); } diff --git a/crates/rune-core/src/lib.rs b/crates/rune-core/src/lib.rs index ecca8a580..c9bbdbd79 100644 --- a/crates/rune-core/src/lib.rs +++ b/crates/rune-core/src/lib.rs @@ -27,10 +27,12 @@ #![no_std] #[cfg(feature = "std")] -extern crate std; +extern crate std as rust_std; #[cfg(feature = "alloc")] -extern crate alloc; +extern crate alloc as rust_alloc; + +pub use rune_alloc as alloc; mod hash; #[doc(hidden)] @@ -56,7 +58,7 @@ pub use self::type_of::FullTypeOf; #[cfg(feature = "std")] #[doc(hidden)] -pub use std::error; +pub use rust_std::error; #[cfg(not(feature = "std"))] pub mod error; diff --git a/crates/rune-core/src/protocol.rs b/crates/rune-core/src/protocol.rs index 11f6afb56..6d2b5e855 100644 --- a/crates/rune-core/src/protocol.rs +++ b/crates/rune-core/src/protocol.rs @@ -3,12 +3,17 @@ use core::fmt; use core::hash::{self, Hash as _}; use core::ops; +use crate as rune; +use crate::alloc::prelude::*; +#[cfg(feature = "alloc")] +use crate::alloc::Error; use crate::hash::IntoHash; use crate::hash::{Hash, ToTypeHash}; use crate::item::ItemBuf; /// A built in instance function. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub struct Protocol { /// The name of the builtin function. @@ -42,8 +47,9 @@ impl ToTypeHash for Protocol { } #[inline] - fn to_item(&self) -> Option { - None + #[cfg(feature = "alloc")] + fn to_item(&self) -> Result, Error> { + Ok(None) } #[inline] @@ -127,7 +133,7 @@ macro_rules! define { #[test] fn ensure_unique_hashes() { - let mut map = ::std::collections::HashMap::<_, &'static str>::new(); + let mut map = ::rust_std::collections::HashMap::<_, &'static str>::new(); $( if let Some(ident) = map.insert($hash, stringify!($ident)) { @@ -470,8 +476,10 @@ define! { /// Signature: `fn(self) -> Result`. /// /// Note that it uses the `Result` like [`std::ops::Try`] uses - /// [`ControlFlow`](std::ops::ControlFlow) i.e., for `Result::` - /// it should return `Result>` + /// [`ControlFlow`] i.e., for `Result::` it should return `Result>` + /// + /// [`ControlFlow`]: std::ops::ControlFlow pub const [TRY, TRY_HASH]: Protocol = Protocol { name: "try", hash: 0x5da1a80787003354u64, diff --git a/crates/rune-core/src/raw_str.rs b/crates/rune-core/src/raw_str.rs index 00bf09324..10b403d3e 100644 --- a/crates/rune-core/src/raw_str.rs +++ b/crates/rune-core/src/raw_str.rs @@ -3,6 +3,9 @@ use core::ops; use core::slice; use core::str; +use crate::alloc; +use crate::alloc::clone::TryClone; + /// A raw static string. /// /// We define and use this instead of relying on `&'static str` (which should @@ -25,6 +28,12 @@ impl RawStr { } } +impl TryClone for RawStr { + fn try_clone(&self) -> alloc::Result { + Ok(*self) + } +} + impl From<&'static str> for RawStr { fn from(s: &'static str) -> Self { Self::from_str(s) diff --git a/crates/rune-core/src/type_of.rs b/crates/rune-core/src/type_of.rs index b8b9a2946..187648cd7 100644 --- a/crates/rune-core/src/type_of.rs +++ b/crates/rune-core/src/type_of.rs @@ -1,7 +1,10 @@ +use crate as rune; +use crate::alloc::prelude::*; use crate::hash::Hash; /// Full type information. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub struct FullTypeOf { #[doc(hidden)] diff --git a/crates/rune-macros/Cargo.toml b/crates/rune-macros/Cargo.toml index 51c743910..99ee43a2d 100644 --- a/crates/rune-macros/Cargo.toml +++ b/crates/rune-macros/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["language", "scripting", "scripting-language"] categories = ["parser-implementations"] [dependencies] -rune-core = { version = "=0.12.3", path = "../rune-core" } +rune-core = { version = "=0.12.3", path = "../rune-core", features = ["std"] } syn = { version = "2.0.16", features = ["full"] } quote = "1.0.27" proc-macro2 = "1.0.56" diff --git a/crates/rune-macros/src/any.rs b/crates/rune-macros/src/any.rs index bcddfce68..5d89d08bf 100644 --- a/crates/rune-macros/src/any.rs +++ b/crates/rune-macros/src/any.rs @@ -245,19 +245,19 @@ fn expand_struct_install_with( }); installers.push(quote! { - module.type_meta::()?.make_named_struct(&[#(#fields,)*])?#constructor.static_docs(&#docs); + module.type_meta::()?.make_named_struct(&[#(#fields,)*])?#constructor.static_docs(&#docs)?; }); } syn::Fields::Unnamed(fields) => { let len = fields.unnamed.len(); installers.push(quote! { - module.type_meta::()?.make_unnamed_struct(#len)?.static_docs(&#docs); + module.type_meta::()?.make_unnamed_struct(#len)?.static_docs(&#docs)?; }); } syn::Fields::Unit => { installers.push(quote! { - module.type_meta::()?.make_empty_struct()?.static_docs(&#docs); + module.type_meta::()?.make_empty_struct()?.static_docs(&#docs)?; }); } } @@ -344,7 +344,7 @@ fn expand_enum_install_with( } variant_metas.push(quote! { - enum_.variant_mut(#variant_index)?.make_named(&[#(#field_names),*])?.static_docs(&#variant_docs) + enum_.variant_mut(#variant_index)?.make_named(&[#(#field_names),*])?.static_docs(&#variant_docs)? }); variants.push((None, variant_attr)); @@ -372,7 +372,7 @@ fn expand_enum_install_with( } variant_metas.push(quote! { - enum_.variant_mut(#variant_index)?.make_unnamed(#fields_len)?.static_docs(&#variant_docs) + enum_.variant_mut(#variant_index)?.make_unnamed(#fields_len)?.static_docs(&#variant_docs)? }); let constructor = if variant_attr.constructor { @@ -390,7 +390,7 @@ fn expand_enum_install_with( } syn::Fields::Unit => { variant_metas.push(quote! { - enum_.variant_mut(#variant_index)?.make_empty()?.static_docs(&#variant_docs) + enum_.variant_mut(#variant_index)?.make_empty()?.static_docs(&#variant_docs)? }); let constructor = if variant_attr.constructor { @@ -448,7 +448,7 @@ fn expand_enum_install_with( } let enum_meta = quote! { - let mut enum_ = module.type_meta::()?.make_enum(&[#(#variant_names,)*])?.static_docs(&#docs); + let mut enum_ = module.type_meta::()?.make_enum(&[#(#variant_names,)*])?.static_docs(&#docs)?; #(#variant_metas;)* }; @@ -468,7 +468,7 @@ fn expand_enum_install_with( let constructor = constructor.as_ref().map(|c| quote!(.constructor(#c)?)); installers - .push(quote!(module.variant_meta::(#index)?#constructor.static_docs(&#docs);)) + .push(quote!(module.variant_meta::(#index)?#constructor.static_docs(&#docs)?;)) } Ok(()) diff --git a/crates/rune-macros/src/context.rs b/crates/rune-macros/src/context.rs index b9e9ba38a..33e26ab0d 100644 --- a/crates/rune-macros/src/context.rs +++ b/crates/rune-macros/src/context.rs @@ -649,6 +649,7 @@ impl Context { variant_data: path(m, ["runtime", "VariantData"]), vm_result: path(m, ["runtime", "VmResult"]), vm_try: path(m, ["vm_try"]), + alloc: path(m, ["alloc"]), } } } @@ -740,6 +741,7 @@ pub(crate) struct Tokens { pub(crate) variant_data: syn::Path, pub(crate) vm_result: syn::Path, pub(crate) vm_try: syn::Path, + pub(crate) alloc: syn::Path, } impl Tokens { diff --git a/crates/rune-macros/src/function.rs b/crates/rune-macros/src/function.rs index f1a214788..c5b37c77d 100644 --- a/crates/rune-macros/src/function.rs +++ b/crates/rune-macros/src/function.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream; -use quote::{quote, ToTokens}; +use quote::{quote, quote_spanned, ToTokens}; use syn::parse::ParseStream; use syn::punctuated::Punctuated; use syn::spanned::Spanned; @@ -24,6 +24,8 @@ pub(crate) struct FunctionAttrs { path: Path, /// Looks like an associated type. self_type: Option, + /// Defines a fallible function which can make use of the `?` operator. + vm_result: bool, } impl FunctionAttrs { @@ -40,6 +42,8 @@ impl FunctionAttrs { out.free = true; } else if ident == "keep" { out.keep = true; + } else if ident == "vm_result" { + out.vm_result = true; } else if ident == "protocol" { input.parse::()?; let protocol: syn::Path = input.parse()?; @@ -186,7 +190,7 @@ impl Function { pub(crate) fn expand(mut self, attrs: FunctionAttrs) -> Result { let instance = attrs.instance || self.takes_self; - let (meta_fn, real_fn, sig, real_fn_mangled) = if attrs.keep { + let (meta_fn, real_fn, mut sig, real_fn_mangled) = if attrs.keep { let meta_fn = syn::Ident::new(&format!("{}__meta", self.sig.ident), self.sig.ident.span()); let real_fn = self.sig.ident.clone(); @@ -331,8 +335,33 @@ impl Function { } stream.extend(self.vis.to_token_stream()); + + let vm_result = VmResult::new(); + + if attrs.vm_result { + let vm_result = &vm_result.vm_result; + + sig.output = match sig.output { + syn::ReturnType::Default => syn::ReturnType::Type( + ]>::default(), + Box::new(syn::Type::Verbatim(quote!(#vm_result<()>))), + ), + syn::ReturnType::Type(arrow, ty) => syn::ReturnType::Type( + arrow, + Box::new(syn::Type::Verbatim(quote!(#vm_result<#ty>))), + ), + }; + } + stream.extend(sig.into_token_stream()); - stream.extend(self.remainder); + + if attrs.vm_result { + let mut block: syn::Block = syn::parse2(self.remainder)?; + vm_result.block(&mut block, true)?; + block.to_tokens(&mut stream); + } else { + stream.extend(self.remainder); + } let arguments = &self.arguments; let docs = &self.docs; @@ -340,9 +369,9 @@ impl Function { let build_with = if instance { None } else if let Some(self_type) = &attrs.self_type { - Some(quote!(.build_associated::<#self_type>())) + Some(quote!(.build_associated::<#self_type>()?)) } else { - Some(quote!(.build())) + Some(quote!(.build()?)) }; let attr = (!real_fn_mangled).then(|| quote!(#[allow(non_snake_case)] #[doc(hidden)])); @@ -352,13 +381,13 @@ impl Function { #[automatically_derived] #attr #[doc(hidden)] - pub(crate) fn #meta_fn() -> rune::__private::FunctionMetaData { - rune::__private::FunctionMetaData { - kind: rune::__private::FunctionMetaKind::#meta_kind(#name, #real_fn_path)#build_with, + pub(crate) fn #meta_fn() -> rune::alloc::Result { + Ok(rune::__private::FunctionMetaData { + kind: rune::__private::FunctionMetaKind::#meta_kind(#name, #real_fn_path)?#build_with, name: #name_string, docs: &#docs[..], arguments: &#arguments[..], - } + }) } }); @@ -390,3 +419,252 @@ fn expr_lit(ident: &syn::Ident) -> syn::Expr { lit: syn::Lit::Str(syn::LitStr::new(&ident.to_string(), ident.span())), }) } + +struct VmResult { + vm_result: syn::Path, + from: syn::Path, + result: syn::Path, +} + +impl VmResult { + fn new() -> Self { + Self { + vm_result: syn::parse_quote!(rune::runtime::VmResult), + from: syn::parse_quote!(core::convert::From), + result: syn::parse_quote!(core::result::Result), + } + } + + /// Modify the block so that it is fallible. + fn block(&self, ast: &mut syn::Block, top_level: bool) -> syn::Result<()> { + let vm_result = &self.vm_result; + + for stmt in &mut ast.stmts { + match stmt { + syn::Stmt::Expr(expr, _) => { + self.expr(expr)?; + } + syn::Stmt::Local(local) => { + if let Some(init) = &mut local.init { + self.expr(&mut init.expr)?; + } + } + _ => {} + }; + } + + if top_level { + let mut found = false; + + for stmt in ast.stmts.iter_mut().rev() { + if let syn::Stmt::Expr(expr, semi) = stmt { + if semi.is_none() { + found = true; + + *expr = syn::Expr::Verbatim(quote_spanned! { + expr.span() => #vm_result::Ok(#expr) + }); + } + + break; + } + } + + if !found { + ast.stmts.push(syn::Stmt::Expr( + syn::Expr::Verbatim(quote!(#vm_result::Ok(()))), + None, + )); + } + } + + Ok(()) + } + + fn expr(&self, ast: &mut syn::Expr) -> syn::Result<()> { + let Self { + vm_result, + from, + result, + } = self; + + let outcome = 'outcome: { + match ast { + syn::Expr::Array(expr) => { + for expr in &mut expr.elems { + self.expr(expr)?; + } + } + syn::Expr::Assign(expt) => { + self.expr(&mut expt.right)?; + } + syn::Expr::Async(..) => {} + syn::Expr::Await(expr) => { + self.expr(&mut expr.base)?; + } + syn::Expr::Binary(expr) => { + self.expr(&mut expr.left)?; + self.expr(&mut expr.right)?; + } + syn::Expr::Block(block) => { + self.block(&mut block.block, false)?; + } + syn::Expr::Break(expr) => { + if let Some(expr) = &mut expr.expr { + self.expr(expr)?; + } + } + syn::Expr::Call(expr) => { + self.expr(&mut expr.func)?; + + for expr in &mut expr.args { + self.expr(expr)?; + } + } + syn::Expr::Field(expr) => { + self.expr(&mut expr.base)?; + } + syn::Expr::ForLoop(expr) => { + self.expr(&mut expr.expr)?; + self.block(&mut expr.body, false)?; + } + syn::Expr::Group(expr) => { + self.expr(&mut expr.expr)?; + } + syn::Expr::If(expr) => { + self.expr(&mut expr.cond)?; + self.block(&mut expr.then_branch, false)?; + + if let Some((_, expr)) = &mut expr.else_branch { + self.expr(expr)?; + } + } + syn::Expr::Index(expr) => { + self.expr(&mut expr.expr)?; + self.expr(&mut expr.index)?; + } + syn::Expr::Let(expr) => { + self.expr(&mut expr.expr)?; + } + syn::Expr::Loop(expr) => { + self.block(&mut expr.body, false)?; + } + syn::Expr::Match(expr) => { + self.expr(&mut expr.expr)?; + + for arm in &mut expr.arms { + if let Some((_, expr)) = &mut arm.guard { + self.expr(expr)?; + } + + self.expr(&mut arm.body)?; + } + } + syn::Expr::MethodCall(expr) => { + self.expr(&mut expr.receiver)?; + + for expr in &mut expr.args { + self.expr(expr)?; + } + } + syn::Expr::Paren(expr) => { + self.expr(&mut expr.expr)?; + } + syn::Expr::Range(expr) => { + if let Some(expr) = &mut expr.start { + self.expr(expr)?; + } + + if let Some(expr) = &mut expr.end { + self.expr(expr)?; + } + } + syn::Expr::Reference(expr) => { + self.expr(&mut expr.expr)?; + } + syn::Expr::Repeat(expr) => { + self.expr(&mut expr.expr)?; + self.expr(&mut expr.len)?; + } + syn::Expr::Return(expr) => { + if let Some(expr) = &mut expr.expr { + self.expr(expr)?; + } + + expr.expr = Some(Box::new(match expr.expr.take() { + Some(expr) => syn::Expr::Verbatim(quote_spanned! { + expr.span() => + #vm_result::Ok(#expr) + }), + None => syn::Expr::Verbatim(quote!(#vm_result::Ok(()))), + })); + } + syn::Expr::Struct(expr) => { + for field in &mut expr.fields { + self.expr(&mut field.expr)?; + } + } + syn::Expr::Try(expr) => { + let span = expr.span(); + + self.expr(&mut expr.expr)?; + + break 'outcome if let Some((expr, ident)) = as_vm_expr(&mut expr.expr) { + let vm_try = syn::Ident::new("vm_try", ident.span()); + quote_spanned!(span => rune::#vm_try!(#expr)) + } else { + let value = &mut expr.expr; + let from = quote_spanned!(expr.question_token.span() => #from::from); + + quote_spanned! { + span => + match #value { + #result::Ok(value) => value, + #result::Err(error) => return #vm_result::Ok(#result::Err(#[allow(clippy::useless_conversion)] #from(error))), + } + } + }; + } + syn::Expr::Tuple(expr) => { + for expr in &mut expr.elems { + self.expr(expr)?; + } + } + syn::Expr::Unary(expr) => { + self.expr(&mut expr.expr)?; + } + syn::Expr::Unsafe(expr) => { + self.block(&mut expr.block, false)?; + } + syn::Expr::While(expr) => { + self.expr(&mut expr.cond)?; + self.block(&mut expr.body, false)?; + } + syn::Expr::Yield(expr) => { + if let Some(expr) = &mut expr.expr { + self.expr(expr)?; + } + } + _ => {} + } + + return Ok(()); + }; + + *ast = syn::Expr::Verbatim(outcome); + Ok(()) + } +} + +/// If this is a field expression like `.vm`. +fn as_vm_expr(expr: &mut syn::Expr) -> Option<(&mut syn::Expr, &syn::Ident)> { + let syn::Expr::Field(expr) = expr else { + return None; + }; + + let syn::Member::Named(ident) = &expr.member else { + return None; + }; + + (ident == "vm").then_some((&mut expr.base, ident)) +} diff --git a/crates/rune-macros/src/hash.rs b/crates/rune-macros/src/hash.rs index 1b9249c21..6ea4e35ac 100644 --- a/crates/rune-macros/src/hash.rs +++ b/crates/rune-macros/src/hash.rs @@ -11,11 +11,14 @@ pub(crate) fn build_type_hash(path: &syn::Path) -> syn::Result { for s in &path.segments { let ident = s.ident.to_string(); - if take(&mut first) { - buf.push(ComponentRef::Crate(&ident)); + let c = if take(&mut first) { + ComponentRef::Crate(&ident) } else { - buf.push(ComponentRef::Str(&ident)); - } + ComponentRef::Str(&ident) + }; + + buf.push(c) + .map_err(|error| syn::Error::new_spanned(s, error))?; match &s.arguments { syn::PathArguments::None => {} diff --git a/crates/rune-macros/src/lib.rs b/crates/rune-macros/src/lib.rs index 360aaed10..f7f918a69 100644 --- a/crates/rune-macros/src/lib.rs +++ b/crates/rune-macros/src/lib.rs @@ -270,14 +270,6 @@ pub fn inst_display(input: proc_macro::TokenStream) -> proc_macro::TokenStream { derive.expand().unwrap_or_else(to_compile_errors).into() } -fn to_compile_errors(errors: I) -> proc_macro2::TokenStream -where - I: IntoIterator, -{ - let compile_errors = errors.into_iter().map(syn::Error::into_compile_error); - ::quote::quote!(#(#compile_errors)*) -} - /// Adds the `path` as trait bound to each generic fn add_trait_bounds(generics: &mut Generics, path: &Path) { for ty in &mut generics.type_params_mut() { @@ -289,3 +281,11 @@ fn add_trait_bounds(generics: &mut Generics, path: &Path) { })); } } + +fn to_compile_errors(errors: I) -> proc_macro2::TokenStream +where + I: IntoIterator, +{ + let compile_errors = errors.into_iter().map(syn::Error::into_compile_error); + ::quote::quote!(#(#compile_errors)*) +} diff --git a/crates/rune-macros/src/macro_.rs b/crates/rune-macros/src/macro_.rs index 7360b19e1..5e7c45d2a 100644 --- a/crates/rune-macros/src/macro_.rs +++ b/crates/rune-macros/src/macro_.rs @@ -182,12 +182,12 @@ impl Macro { stream.extend(quote! { /// Get function metadata. #[automatically_derived] - #meta_vis fn #meta_fn() -> rune::__private::MacroMetaData { - rune::__private::MacroMetaData { - kind: rune::__private::MacroMetaKind::#macro_kind(#meta_name, #real_fn_path), + #meta_vis fn #meta_fn() -> rune::alloc::Result { + Ok(rune::__private::MacroMetaData { + kind: rune::__private::MacroMetaKind::#macro_kind(#meta_name, #real_fn_path)?, name: #name_string, docs: &#docs[..], - } + }) } }); diff --git a/crates/rune-macros/src/module.rs b/crates/rune-macros/src/module.rs index f1aa458a2..113d6b670 100644 --- a/crates/rune-macros/src/module.rs +++ b/crates/rune-macros/src/module.rs @@ -76,18 +76,18 @@ impl Module { let item = build_item(it); if item.elems.is_empty() { - quote!(rune::__private::ItemBuf::with_crate(#krate)) + quote!(rune::__private::ItemBuf::with_crate(#krate)?) } else { - quote!(rune::__private::ItemBuf::with_crate_item(#krate, #item)) + quote!(rune::__private::ItemBuf::with_crate_item(#krate, #item)?) } } None => { let item = build_item(attrs.path.segments.iter()); if item.elems.is_empty() { - quote!(rune::__private::ItemBuf::new()) + quote!(rune::__private::ItemBuf::new()?) } else { - quote!(rune::__private::ItemBuf::from_item(#item)) + quote!(rune::__private::ItemBuf::from_item(#item)?) } } }; @@ -98,11 +98,11 @@ impl Module { /// Get module metadata. #[automatically_derived] #[doc(hidden)] - fn module_meta() -> rune::__private::ModuleMetaData { - rune::__private::ModuleMetaData { + fn module_meta() -> rune::alloc::Result { + Ok(rune::__private::ModuleMetaData { docs: &#docs[..], item: #item, - } + }) } }); diff --git a/crates/rune-macros/src/quote.rs b/crates/rune-macros/src/quote.rs index 4ee9ab0d7..384418e06 100644 --- a/crates/rune-macros/src/quote.rs +++ b/crates/rune-macros/src/quote.rs @@ -26,9 +26,12 @@ impl Quote { /// Parse the given input stream and convert into code that constructs a /// `ToTokens` implementation. pub fn parse(&self, input: TokenStream) -> Result { + let mut output = self.process(input)?; + output.push(("Ok", p(p(())))); + let arg = ( ("move", '|', self.cx, ',', self.stream, '|'), - braced(self.process(input)?), + braced(output), ); let mut output = Builder::new(); @@ -169,6 +172,7 @@ impl Quote { ( ToTokensFn, p(('&', "value", ',', self.cx, ',', self.stream)), + '?', ';', ), ("if", "it", '.', "peek", p(()), '.', "is_some", p(())), @@ -200,7 +204,7 @@ impl Quote { ( ToTokensFn, p(('&', tokens, ',', self.cx, ',', self.stream)), - ';', + ('?', ';'), ), ); } diff --git a/crates/rune-macros/src/quote/inner.rs b/crates/rune-macros/src/quote/inner.rs index ed8891601..4183cec7f 100644 --- a/crates/rune-macros/src/quote/inner.rs +++ b/crates/rune-macros/src/quote/inner.rs @@ -178,7 +178,7 @@ pub(crate) struct NewIdent<'a>(pub(crate) &'static str, pub(crate) &'a str); impl ToTokens for NewIdent<'_> { fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) { - (self.0, '.', "ident", p(p::Literal::string(self.1))).to_tokens(stream, span); + (self.0, '.', "ident", p(p::Literal::string(self.1)), '?').to_tokens(stream, span); } } @@ -187,6 +187,6 @@ pub(crate) struct NewLit(pub(crate) &'static str, pub(crate) p::Literal); impl ToTokens for NewLit { fn to_tokens(self, stream: &mut p::TokenStream, span: p::Span) { - (self.0, '.', "lit", p(self.1)).to_tokens(stream, span); + (self.0, '.', "lit", p(self.1), '?').to_tokens(stream, span); } } diff --git a/crates/rune-macros/src/to_tokens.rs b/crates/rune-macros/src/to_tokens.rs index 63e537d33..f3d276558 100644 --- a/crates/rune-macros/src/to_tokens.rs +++ b/crates/rune-macros/src/to_tokens.rs @@ -1,9 +1,7 @@ -use crate::{ - add_trait_bounds, - context::{Context, Tokens}, -}; +use crate::add_trait_bounds; +use crate::context::{Context, Tokens}; use proc_macro2::TokenStream; -use quote::quote_spanned; +use quote::{quote, quote_spanned}; use syn::spanned::Spanned as _; /// Derive implementation of the ToTokens macro. @@ -81,9 +79,13 @@ impl Expander { } let ident = &input.ident; - let to_tokens = &self.tokens.to_tokens; - let macro_context = &self.tokens.macro_context; - let token_stream = &self.tokens.token_stream; + let Tokens { + to_tokens, + macro_context, + token_stream, + alloc, + .. + } = &self.tokens; let mut generics = input.generics.clone(); @@ -91,13 +93,15 @@ impl Expander { let (impl_generics, type_generics, where_generics) = generics.split_for_impl(); - Ok(quote_spanned! { input.span() => + Ok(quote! { #[automatically_derived] impl #impl_generics #to_tokens for #ident #type_generics #where_generics { - fn to_tokens(&self, context: &mut #macro_context, stream: &mut #token_stream) { + fn to_tokens(&self, context: &mut #macro_context, stream: &mut #token_stream) -> #alloc::Result<()> { match self { - #(#impl_into_tokens,)* + #(#impl_into_tokens),* } + + Ok(()) } } }) @@ -149,6 +153,14 @@ impl Expander { ) -> Result { let mut fields = Vec::new(); + let Tokens { + to_tokens, + macro_context, + token_stream, + alloc, + .. + } = &self.tokens; + for field in &named.named { let ident = self.cx.field_ident(field)?; let attrs = self.cx.field_attrs(&field.attrs)?; @@ -157,15 +169,11 @@ impl Expander { continue; } - fields.push(quote_spanned! { field.span() => self.#ident.to_tokens(context, stream) }) + fields.push(quote! { #to_tokens::to_tokens(&self.#ident, context, stream)? }) } let ident = &input.ident; - let to_tokens = &self.tokens.to_tokens; - let macro_context = &self.tokens.macro_context; - let token_stream = &self.tokens.token_stream; - let mut generics = input.generics.clone(); add_trait_bounds(&mut generics, to_tokens); @@ -175,8 +183,9 @@ impl Expander { let into_tokens_impl = quote_spanned! { named.span() => #[automatically_derived] impl #impl_generics #to_tokens for #ident #type_generics #where_generics { - fn to_tokens(&self, context: &mut #macro_context, stream: &mut #token_stream) { + fn to_tokens(&self, context: &mut #macro_context, stream: &mut #token_stream) -> #alloc::Result<()> { #(#fields;)* + Ok(()) } } }; @@ -195,6 +204,8 @@ impl Expander { let mut fields = Vec::new(); let mut idents = Vec::new(); + let Tokens { to_tokens, .. } = &self.tokens; + for field in &named.named { let ident = self.cx.field_ident(field)?; let attrs = self.cx.field_attrs(&field.attrs)?; @@ -204,12 +215,12 @@ impl Expander { continue; } - fields.push(quote_spanned! { field.span() => #ident.to_tokens(context, stream) }) + fields.push(quote! { #to_tokens::to_tokens(&#ident, context, stream)? }) } let ident = &variant.ident; - Ok(quote_spanned! { named.span() => + Ok(quote! { Self::#ident { #(#idents,)* } => { #(#fields;)* } }) } @@ -223,6 +234,8 @@ impl Expander { let mut field_into_tokens = Vec::new(); let mut idents = Vec::new(); + let Tokens { to_tokens, .. } = &self.tokens; + for (n, field) in named.unnamed.iter().enumerate() { let ident = syn::Ident::new(&format!("f{}", n), field.span()); let attrs = self.cx.field_attrs(&field.attrs)?; @@ -233,13 +246,12 @@ impl Expander { continue; } - field_into_tokens - .push(quote_spanned! { field.span() => #ident.to_tokens(context, stream) }) + field_into_tokens.push(quote! { #to_tokens::to_tokens(#ident, context, stream)? }) } let ident = &variant.ident; - Ok(quote_spanned! { named.span() => + Ok(quote! { Self::#ident(#(#idents,)*) => { #(#field_into_tokens;)* } }) } diff --git a/crates/rune-modules/src/experiments.rs b/crates/rune-modules/src/experiments.rs index 3a87f694a..c44c89c0c 100644 --- a/crates/rune-modules/src/experiments.rs +++ b/crates/rune-modules/src/experiments.rs @@ -15,9 +15,10 @@ //! ```rust //! let mut context = rune::Context::with_default_modules()?; //! context.install(rune_modules::experiments::module(true)?)?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` +use rune::alloc::prelude::*; use rune::ast; use rune::compile; use rune::macros::{quote, MacroContext, TokenStream}; @@ -29,7 +30,7 @@ mod stringy_math_macro; /// Construct the `std::experiments` module, which contains experiments. pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate_item("std", ["experiments"]); + let mut module = Module::with_crate_item("std", ["experiments"])?; module.macro_meta(passthrough)?; module.macro_meta(stringy_math_macro::stringy_math)?; module.macro_meta(make_function)?; @@ -42,7 +43,7 @@ fn passthrough( _: &mut MacroContext<'_, '_, '_>, stream: &TokenStream, ) -> compile::Result { - Ok(stream.clone()) + Ok(stream.try_clone()?) } /// Implementation for the `make_function!` macro. @@ -58,5 +59,5 @@ fn make_function( let output = parser.parse::()?; parser.eof()?; - Ok(quote!(fn #ident() { #output }).into_token_stream(cx)) + Ok(quote!(fn #ident() { #output }).into_token_stream(cx)?) } diff --git a/crates/rune-modules/src/experiments/stringy_math_macro.rs b/crates/rune-modules/src/experiments/stringy_math_macro.rs index 2a1fff568..1bd0d1f73 100644 --- a/crates/rune-modules/src/experiments/stringy_math_macro.rs +++ b/crates/rune-modules/src/experiments/stringy_math_macro.rs @@ -27,5 +27,5 @@ pub(crate) fn stringy_math( } parser.eof()?; - Ok(output.into_token_stream(cx)) + Ok(output.into_token_stream(cx)?) } diff --git a/crates/rune-modules/src/fs.rs b/crates/rune-modules/src/fs.rs index a1967f3a5..5e7a3f9fb 100644 --- a/crates/rune-modules/src/fs.rs +++ b/crates/rune-modules/src/fs.rs @@ -15,7 +15,7 @@ //! ```rust //! let mut context = rune::Context::with_default_modules()?; //! context.install(rune_modules::fs::module(true)?)?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` //! //! Use it in Rune: @@ -33,7 +33,7 @@ use rune::{Module, ContextError}; /// Construct the `fs` module. pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate("fs"); + let mut module = Module::with_crate("fs")?; module.function(["read_to_string"], read_to_string)?; Ok(module) } diff --git a/crates/rune-modules/src/http.rs b/crates/rune-modules/src/http.rs index d3b535738..2f6b22847 100644 --- a/crates/rune-modules/src/http.rs +++ b/crates/rune-modules/src/http.rs @@ -16,7 +16,7 @@ //! let mut context = rune::Context::with_default_modules()?; //! context.install(rune_modules::http::module(true)?)?; //! context.install(rune_modules::json::module(true)?)?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` //! //! Use it in Rune: @@ -50,11 +50,11 @@ use rune::{Any, Module, Value, ContextError}; use rune::runtime::{Bytes, Ref, Formatter, VmResult}; -use rune::alloc::TryWrite; +use rune::alloc::fmt::TryWrite; /// Construct the `http` module. pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate("http"); + let mut module = Module::with_crate("http")?; module.ty::()?; module.ty::()?; @@ -194,7 +194,7 @@ impl RequestBuilder { let bytes = bytes.into_vec(); Self { - request: self.request.body(bytes), + request: self.request.body(bytes.into_std()), } } } diff --git a/crates/rune-modules/src/json.rs b/crates/rune-modules/src/json.rs index b9d9eca92..762bfd143 100644 --- a/crates/rune-modules/src/json.rs +++ b/crates/rune-modules/src/json.rs @@ -15,7 +15,7 @@ //! ```rust //! let mut context = rune::Context::with_default_modules()?; //! context.install(rune_modules::json::module(true)?)?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` //! //! Use it in Rune: @@ -29,35 +29,68 @@ //! } //! ``` -use rune::{ContextError, Module}; -use rune::runtime::{Bytes, Value}; +use rune::{ContextError, Module, vm_write, Any}; +use rune::runtime::{Bytes, Value, Formatter}; +use rune::alloc::{Vec, String}; +use rune::alloc::fmt::TryWrite; /// Construct the `json` module. pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate("json"); - module.function(["from_bytes"], from_bytes)?; - module.function(["from_string"], from_string)?; - module.function(["to_string"], to_string)?; - module.function(["to_bytes"], to_bytes)?; + let mut module = Module::with_crate("json")?; + module.ty::()?; + module.function_meta(Error::display)?; + module.function_meta(Error::debug)?; + module.function_meta(from_bytes)?; + module.function_meta(from_string)?; + module.function_meta(to_string)?; + module.function_meta(to_bytes)?; Ok(module) } -fn from_bytes(bytes: &[u8]) -> rune::Result { +#[derive(Any)] +#[rune(item = ::json)] +struct Error { + error: serde_json::Error, +} + +impl Error { + #[rune::function(vm_result, protocol = STRING_DISPLAY)] + pub(crate) fn display(&self, f: &mut Formatter) { + vm_write!(f, "{}", self.error); + } + + #[rune::function(vm_result, protocol = STRING_DEBUG)] + pub(crate) fn debug(&self, f: &mut Formatter) { + vm_write!(f, "{:?}", self.error); + } +} + +impl From for Error { + fn from(error: serde_json::Error) -> Self { + Self { error } + } +} + +/// Convert JSON bytes into a rune value. +#[rune::function] +fn from_bytes(bytes: &[u8]) -> Result { Ok(serde_json::from_slice(bytes)?) } -/// Get value from json string. -fn from_string(string: &str) -> rune::Result { +/// Convert a JSON string into a rune value. +#[rune::function] +fn from_string(string: &str) -> Result { Ok(serde_json::from_str(string)?) } /// Convert any value to a json string. -fn to_string(value: Value) -> rune::Result { - Ok(serde_json::to_string(&value)?) +#[rune::function(vm_result)] +fn to_string(value: Value) -> Result { + Ok(String::try_from(serde_json::to_string(&value)?).vm?) } /// Convert any value to json bytes. -fn to_bytes(value: Value) -> rune::Result { - let bytes = serde_json::to_vec(&value)?; - Ok(Bytes::from_vec(bytes)) +#[rune::function(vm_result)] +fn to_bytes(value: Value) -> Result { + Ok(Bytes::from_vec(Vec::try_from(serde_json::to_vec(&value)?).vm?)) } diff --git a/crates/rune-modules/src/lib.rs b/crates/rune-modules/src/lib.rs index 986e41803..55b9e5a3e 100644 --- a/crates/rune-modules/src/lib.rs +++ b/crates/rune-modules/src/lib.rs @@ -83,7 +83,7 @@ pub mod experiments; macro_rules! modules { - ($($ident:ident, $name:literal),* $(,)?) => { + ($({$ident:ident, $name:literal $(, $module:ident)*}),* $(,)?) => { $( #[cfg(feature = $name)] pub mod $ident; @@ -101,6 +101,7 @@ macro_rules! modules { #[cfg(feature = $name)] { context.install(self::$ident::module(stdio)?)?; + $(context.install(self::$ident::$module::module(stdio)?)?;)* } )* @@ -115,17 +116,17 @@ macro_rules! modules { } modules! { - core, "core", - fmt, "fmt", - fs, "fs", - http, "http", - io, "io", - json, "json", - macros, "macros", - process, "process", - rand, "rand", - signal, "signal", - test, "test", - time, "time", - toml, "toml", + {core, "core"}, + {fmt, "fmt"}, + {fs, "fs"}, + {http, "http"}, + {io, "io"}, + {json, "json"}, + {macros, "macros"}, + {process, "process"}, + {rand, "rand"}, + {signal, "signal"}, + {test, "test"}, + {time, "time"}, + {toml, "toml", ser, de}, } diff --git a/crates/rune-modules/src/process.rs b/crates/rune-modules/src/process.rs index 086756697..bb1a1aa51 100644 --- a/crates/rune-modules/src/process.rs +++ b/crates/rune-modules/src/process.rs @@ -15,7 +15,7 @@ //! ```rust //! let mut context = rune::Context::with_default_modules()?; //! context.install(rune_modules::process::module(true)?)?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` //! //! Use it in Rune: @@ -29,15 +29,17 @@ //! } //! ``` -use rune::{Any, Module, ContextError}; +use rune::{Any, Module, ContextError, vm_try}; use rune::runtime::{Bytes, Shared, Value, VmResult, Formatter}; -use rune::alloc::TryWrite; +use rune::alloc::fmt::TryWrite; +use rune::alloc::Vec; + use std::io; use tokio::process; /// Construct the `process` module. pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate("process"); + let mut module = Module::with_crate("process")?; module.ty::()?; module.ty::()?; module.ty::()?; @@ -74,10 +76,10 @@ impl Command { for arg in args { match arg { Value::String(s) => { - self.inner.arg(&*rune::vm_try!(s.borrow_ref())); + self.inner.arg(&*vm_try!(s.borrow_ref())); } actual => { - return VmResult::expected::(rune::vm_try!(actual.type_info())); + return VmResult::expected::(vm_try!(actual.type_info())); } } } @@ -113,25 +115,22 @@ struct Child { impl Child { // Returns a future that will resolve to an Output, containing the exit // status, stdout, and stderr of the child process. - #[rune::function(instance)] - async fn wait_with_output(self) -> VmResult> { + #[rune::function(vm_result, instance)] + async fn wait_with_output(self) -> io::Result { let inner = match self.inner { Some(inner) => inner, None => { - return VmResult::panic("already completed"); + rune::vm_panic!("already completed"); } }; - let output = match inner.wait_with_output().await { - Ok(output) => output, - Err(error) => return VmResult::Ok(Err(error)), - }; + let output = inner.wait_with_output().await?; - VmResult::Ok(Ok(Output { + Ok(Output { status: ExitStatus { status: output.status }, - stdout: rune::vm_try!(Shared::new(Bytes::from_vec(output.stdout))), - stderr: rune::vm_try!(Shared::new(Bytes::from_vec(output.stderr))), - })) + stdout: Shared::new(Bytes::from_vec(Vec::try_from(output.stdout).vm?)).vm?, + stderr: Shared::new(Bytes::from_vec(Vec::try_from(output.stderr).vm?)).vm?, + }) } } diff --git a/crates/rune-modules/src/rand.rs b/crates/rune-modules/src/rand.rs index fd5428402..1d712f545 100644 --- a/crates/rune-modules/src/rand.rs +++ b/crates/rune-modules/src/rand.rs @@ -16,7 +16,7 @@ //! ```rust //! let mut context = rune::Context::with_default_modules()?; //! context.install(rune_modules::rand::module(true)?)?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` //! //! Use it in Rune: @@ -37,7 +37,7 @@ use rune::runtime::Value; /// Construct the `rand` module. pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate("rand"); + let mut module = Module::with_crate("rand")?; module.ty::()?; module.function(["WyRand", "new"], WyRand::new)?; @@ -121,13 +121,13 @@ impl Pcg64 { } } -fn int() -> rune::Result { +fn int() -> rune::support::Result { Ok(Value::Integer( nanorand::WyRand::new().generate::() as i64 )) } -fn int_range(lower: i64, upper: i64) -> rune::Result { +fn int_range(lower: i64, upper: i64) -> rune::support::Result { Ok(Value::Integer( nanorand::WyRand::new().generate_range(0..(upper - lower) as u64) as i64 + lower, )) diff --git a/crates/rune-modules/src/signal.rs b/crates/rune-modules/src/signal.rs index 15d087bab..aec3b29be 100644 --- a/crates/rune-modules/src/signal.rs +++ b/crates/rune-modules/src/signal.rs @@ -15,7 +15,7 @@ //! ```rust //! let mut context = rune::Context::with_default_modules()?; //! context.install(rune_modules::signal::module(true)?)?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` //! //! Use it in Rune: @@ -33,7 +33,7 @@ use rune::{Module, ContextError}; /// Construct the `signal` module. pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate("signal"); + let mut module = Module::with_crate("signal")?; module.function_meta(ctrl_c)?; Ok(module) } diff --git a/crates/rune-modules/src/time.rs b/crates/rune-modules/src/time.rs index 7f69fda5a..b1c44b462 100644 --- a/crates/rune-modules/src/time.rs +++ b/crates/rune-modules/src/time.rs @@ -15,7 +15,7 @@ //! ```rust //! let mut context = rune::Context::with_default_modules()?; //! context.install(rune_modules::time::module(true)?)?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` //! //! Use it in Rune: @@ -33,7 +33,7 @@ use rune::{Any, ContextError, Module}; /// Construct the `time` module. pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate("time"); + let mut module = Module::with_crate("time")?; module.ty::()?; module.function_meta(Duration::from_secs__meta)?; module.function_meta(sleep)?; diff --git a/crates/rune-modules/src/toml.rs b/crates/rune-modules/src/toml.rs index 862aecef0..90b268c66 100644 --- a/crates/rune-modules/src/toml.rs +++ b/crates/rune-modules/src/toml.rs @@ -15,7 +15,7 @@ //! ```rust //! let mut context = rune::Context::with_default_modules()?; //! context.install(rune_modules::toml::module(true)?)?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` //! //! Use it in Rune: @@ -31,34 +31,129 @@ use rune::{ContextError, Module}; use rune::runtime::{Bytes, Value}; +use rune::alloc::String; /// Construct the `toml` module. pub fn module(_stdio: bool) -> Result { - let mut module = Module::with_crate("toml"); - module.function(["from_bytes"], from_bytes)?; - module.function(["from_string"], from_string)?; - module.function(["to_string"], to_string)?; - module.function(["to_bytes"], to_bytes)?; + let mut module = Module::with_crate("toml")?; + module.function_meta(from_bytes)?; + module.function_meta(from_string)?; + module.function_meta(to_string)?; + module.function_meta(to_bytes)?; Ok(module) } -fn from_bytes(bytes: &[u8]) -> rune::Result { - let bytes = std::str::from_utf8(bytes)?; - Ok(toml::from_str(bytes)?) +pub mod de { + //! Deserializer types for the toml module. + + use rune::{Any, Module, ContextError, vm_write}; + use rune::runtime::{Formatter, VmResult}; + use rune::alloc::fmt::TryWrite; + + pub fn module(_stdio: bool) -> Result { + let mut module = Module::with_crate_item("toml", ["de"])?; + module.ty::()?; + module.function_meta(Error::display)?; + module.function_meta(Error::debug)?; + Ok(module) + } + + #[derive(Any)] + #[rune(item = ::toml::de)] + pub(crate) struct Error { + pub(crate) error: toml::de::Error, + } + + impl Error { + #[rune::function(protocol = STRING_DISPLAY)] + pub(crate) fn display(&self, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{}", self.error); + VmResult::Ok(()) + } + + #[rune::function(protocol = STRING_DEBUG)] + pub(crate) fn debug(&self, f: &mut Formatter) -> VmResult<()> { + vm_write!(f, "{:?}", self.error); + VmResult::Ok(()) + } + } + + impl From for Error { + fn from(error: toml::de::Error) -> Self { + Self { error } + } + } +} + +pub mod ser { + //! Serializer types for the toml module. + + use rune::{Any, Module, ContextError, vm_write}; + use rune::runtime::Formatter; + use rune::alloc::fmt::TryWrite; + + pub fn module(_stdio: bool) -> Result { + let mut module = Module::with_crate_item("toml", ["ser"])?; + module.ty::()?; + module.function_meta(Error::display)?; + module.function_meta(Error::debug)?; + Ok(module) + } + + #[derive(Any)] + #[rune(item = ::toml::ser)] + pub(crate) struct Error { + pub(crate) error: toml::ser::Error, + } + + impl Error { + #[rune::function(vm_result, protocol = STRING_DISPLAY)] + pub(crate) fn display(&self, f: &mut Formatter) { + vm_write!(f, "{}", self.error); + } + + #[rune::function(vm_result, protocol = STRING_DEBUG)] + pub(crate) fn debug(&self, f: &mut Formatter) { + vm_write!(f, "{:?}", self.error); + } + } + + impl From for Error { + fn from(error: toml::ser::Error) -> Self { + Self { error } + } + } +} + +/// Convert bytes of TOML into a rune value. +#[rune::function(vm_result)] +fn from_bytes(bytes: &[u8]) -> Result { + let bytes = match std::str::from_utf8(bytes) { + Ok(bytes) => bytes, + Err(error) => return Err(rune::to_value(error).vm?), + }; + + match toml::from_str(bytes).map_err(de::Error::from) { + Ok(value) => Ok(value), + Err(error) => Err(rune::to_value(error).vm?), + } } -/// Get value from toml string. -fn from_string(string: &str) -> rune::Result { +/// Convert a string of TOML into a rune value. +#[rune::function] +fn from_string(string: &str) -> Result { Ok(toml::from_str(string)?) } /// Convert any value to a toml string. -fn to_string(value: Value) -> rune::Result { - Ok(toml::to_string(&value)?) +#[rune::function(vm_result)] +fn to_string(value: Value) -> Result { + Ok(String::try_from(toml::to_string(&value)?).vm?) } /// Convert any value to toml bytes. -fn to_bytes(value: Value) -> rune::Result { - let bytes = toml::to_string(&value)?.into_bytes(); - Ok(Bytes::from_vec(bytes)) +#[rune::function(vm_result)] +fn to_bytes(value: Value) -> Result { + let string = String::try_from(toml::to_string(&value)?).vm?; + Ok(Bytes::from_vec(string.into_bytes())) } diff --git a/crates/rune-wasm/src/http.rs b/crates/rune-wasm/src/http.rs index fa6c75414..26775dd91 100644 --- a/crates/rune-wasm/src/http.rs +++ b/crates/rune-wasm/src/http.rs @@ -5,7 +5,7 @@ use wasm_bindgen_futures::JsFuture; /// The wasm `http` module. pub fn module() -> Result { - let mut module = Module::with_crate("http"); + let mut module = Module::with_crate("http")?; module.ty::()?; module.ty::()?; module.function(["get"], get)?; diff --git a/crates/rune-wasm/src/lib.rs b/crates/rune-wasm/src/lib.rs index ebbd54eb4..87ab832eb 100644 --- a/crates/rune-wasm/src/lib.rs +++ b/crates/rune-wasm/src/lib.rs @@ -155,6 +155,8 @@ fn setup_context(experimental: bool, io: &CaptureIo) -> Result execution, diff --git a/crates/rune-wasm/src/time.rs b/crates/rune-wasm/src/time.rs index 2e323f22f..d42610962 100644 --- a/crates/rune-wasm/src/time.rs +++ b/crates/rune-wasm/src/time.rs @@ -11,7 +11,7 @@ extern "C" { /// The wasm 'time' module. pub fn module() -> Result { - let mut module = Module::with_crate("time"); + let mut module = Module::with_crate("time")?; module.ty::()?; module.function(["Duration", "from_secs"], Duration::from_secs)?; module.function(["delay_for"], delay_for)?; diff --git a/crates/rune/Cargo.toml b/crates/rune/Cargo.toml index d73fd42fa..baeada546 100644 --- a/crates/rune/Cargo.toml +++ b/crates/rune/Cargo.toml @@ -25,13 +25,13 @@ byte-code = ["alloc", "musli-storage"] capture-io = ["alloc", "parking_lot"] disable-io = ["alloc"] fmt = ["alloc"] -std = ["num/std", "serde/std", "rune-core/std", "rune-alloc/std", "musli/std", "musli-storage/std", "alloc", "anyhow", "once_cell/std"] -alloc = ["rune-alloc/alloc", "rune-core/alloc", "once_cell/alloc"] +std = ["alloc", "num/std", "serde/std", "rune-core/std", "rune-alloc/std", "musli/std", "musli-storage/std", "once_cell/std", "anyhow/std"] +alloc = ["anyhow", "rune-alloc/alloc", "rune-core/alloc", "once_cell/alloc", "serde/alloc"] [dependencies] rune-macros = { version = "=0.12.3", path = "../rune-macros" } rune-core = { version = "=0.12.3", path = "../rune-core", features = ["musli"] } -rune-alloc = { version = "=0.12.3", path = "../rune-alloc", default-features = false } +rune-alloc = { version = "=0.12.3", path = "../rune-alloc", features = ["serde"], default-features = false } futures-core = { version = "0.3.28", default-features = false } futures-util = { version = "0.3.28", default-features = false, features = ["alloc"] } @@ -39,17 +39,14 @@ itoa = "1.0.6" num = { version = "0.4.0", default-features = false, features = ["alloc"] } pin-project = "1.1.0" ryu = "1.0.13" -serde = { version = "1.0.163", default-features = false, features = ["derive", "alloc", "rc"] } -serde_bytes = { version = "0.11.9", default-features = false, features = ["alloc"] } -smallvec = { version = "1.10.0", default-features = false, features = ["serde", "const_new"] } +serde = { version = "1.0.163", default-features = false, features = ["derive", "rc"] } tracing = { version = "0.1.37", default-features = false, features = ["attributes"] } -hashbrown = { version = "0.14.0", features = ["serde"] } musli = { version = "0.0.42", default-features = false, features = ["alloc"] } slab = { version = "0.4.8", default-features = false } once_cell = { version = "1.18.0", default-features = false, features = ["critical-section"] } musli-storage = { version = "0.0.42", default-features = false, optional = true, features = ["alloc"] } -anyhow = { version = "1.0.71", features = ["std"], optional = true } +anyhow = { version = "1.0.71", default-features = false, optional = true } atty = { version = "0.2.14", optional = true } bincode = { version = "1.3.3", optional = true } clap = { version = "4.2.7", features = ["derive"], optional = true } diff --git a/crates/rune/README.md b/crates/rune/README.md index 7df625879..217270553 100644 --- a/crates/rune/README.md +++ b/crates/rune/README.md @@ -80,9 +80,9 @@ use rune::termcolor::{ColorChoice, StandardStream}; use std::sync::Arc; #[tokio::main] -async fn main() -> rune::Result<()> { +async fn main() -> rune::support::Result<()> { let context = Context::with_default_modules()?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = Sources::new(); sources.insert(Source::new( diff --git a/crates/rune/src/any.rs b/crates/rune/src/any.rs index 3ec26a4cc..67526668c 100644 --- a/crates/rune/src/any.rs +++ b/crates/rune/src/any.rs @@ -27,7 +27,7 @@ use crate::hash::Hash; /// } /// /// fn install() -> Result { -/// let mut module = rune::Module::with_crate("process"); +/// let mut module = rune::Module::with_crate("process")?; /// module.ty::()?; /// Ok(module) /// } @@ -81,6 +81,7 @@ pub trait Any: Named + any::Any { // Internal any impls for useful types in the std library. -crate::__internal_impl_any!(::std::fmt, crate::no_std::fmt::Error); -crate::__internal_impl_any!(::std::io, crate::no_std::io::Error); -crate::__internal_impl_any!(::std::error, crate::no_std::Error); +crate::__internal_impl_any!(::std::fmt, core::fmt::Error); +#[cfg(feature = "std")] +crate::__internal_impl_any!(::std::io, std::io::Error); +crate::__internal_impl_any!(::std::error, anyhow::Error); diff --git a/crates/rune/src/ast.rs b/crates/rune/src/ast.rs index ab5b12c18..20ba37598 100644 --- a/crates/rune/src/ast.rs +++ b/crates/rune/src/ast.rs @@ -12,25 +12,26 @@ //! use rune::compile; //! use rune::macros::{quote, MacroContext, TokenStream}; //! use rune::parse::Parser; +//! use rune::alloc::prelude::*; +//! //! use std::sync::Arc; //! //! #[rune::macro_] //! fn ident_to_string(cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream) -> compile::Result { //! let mut p = Parser::from_token_stream(stream, cx.input_span()); //! let ident = p.parse_all::()?; -//! let ident = cx.resolve(ident)?.to_owned(); -//! let string = cx.lit(&ident); -//! Ok(quote!(#string).into_token_stream(cx)) +//! let ident = cx.resolve(ident)?.try_to_owned()?; +//! let string = cx.lit(&ident)?; +//! Ok(quote!(#string).into_token_stream(cx)?) //! } //! -//! # fn main() -> rune::Result<()> { //! let mut m = Module::new(); //! m.macro_meta(ident_to_string)?; //! //! let mut context = Context::new(); //! context.install(m)?; //! -//! let runtime = Arc::new(context.runtime()); +//! let runtime = Arc::new(context.runtime()?); //! //! let mut sources = rune::sources! { //! entry => { @@ -51,10 +52,11 @@ //! let value: String = rune::from_value(value)?; //! //! assert_eq!(value, "hello"); -//! # Ok(()) -//! # } +//! # Ok::<_, rune::support::Error>(()) //! ``` +use crate as rune; +use crate::alloc::prelude::*; use crate::macros::{MacroContext, ToTokens, TokenStream}; use crate::parse::{Parse, Parser, Peek}; @@ -234,7 +236,8 @@ macro_rules! decl_tokens { ($(($parser:ident, $name:expr, $doc:expr, $($kind:tt)*),)*) => { $( #[doc = $doc] - #[derive(Debug, Clone, Copy, PartialEq, Eq)] + #[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq)] + #[try_clone(copy)] pub struct $parser { /// Associated token. pub span: Span, @@ -270,8 +273,8 @@ macro_rules! decl_tokens { } impl ToTokens for $parser { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { - stream.push(Token { span: self.span, kind: $($kind)* }); + fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) -> alloc::Result<()> { + stream.push(Token { span: self.span, kind: $($kind)* }) } } )* @@ -290,7 +293,8 @@ decl_tokens! { } /// The composite `is not` operation. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ToTokens, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Hash, ToTokens, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub struct IsNot { /// The `is` token. diff --git a/crates/rune/src/ast/attribute.rs b/crates/rune/src/ast/attribute.rs index 08756f547..becf3ec28 100644 --- a/crates/rune/src/ast/attribute.rs +++ b/crates/rune/src/ast/attribute.rs @@ -43,7 +43,7 @@ fn ast_parse() { /// /// * `#[derive(Debug)]`. /// * `#![doc = "test"]`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct Attribute { /// The `#` character @@ -98,7 +98,7 @@ impl Parse for Attribute { break; } - input.push(token); + input.push(token)?; } Ok(Attribute { @@ -132,7 +132,8 @@ impl IntoExpectation for Attribute { } /// Whether or not the attribute is an outer `#!` or inner `#` attribute -#[derive(Debug, Clone, Copy, PartialEq, Eq, OptionSpanned, ToTokens)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, OptionSpanned, ToTokens)] +#[try_clone(copy)] #[non_exhaustive] pub enum AttrStyle { /// `#` diff --git a/crates/rune/src/ast/block.rs b/crates/rune/src/ast/block.rs index 815bff9f9..73356e991 100644 --- a/crates/rune/src/ast/block.rs +++ b/crates/rune/src/ast/block.rs @@ -46,7 +46,7 @@ fn ast_parse() { /// A block of statements. /// /// * `{ ()* }`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned, Opaque)] #[non_exhaustive] pub struct Block { /// The unique identifier for the block expression. @@ -68,7 +68,7 @@ impl Parse for Block { let open = parser.parse()?; while !parser.peek::()? { - statements.push(parser.parse()?); + statements.try_push(parser.parse()?)?; } let close = parser.parse()?; @@ -85,7 +85,7 @@ impl Parse for Block { /// A block of statements. /// /// * `{ ()* }`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Opaque)] #[non_exhaustive] pub struct EmptyBlock { /// The unique identifier for the block expression. @@ -100,7 +100,7 @@ impl Parse for EmptyBlock { let mut statements = Vec::new(); while !parser.is_eof()? { - statements.push(parser.parse()?); + statements.try_push(parser.parse()?)?; } Ok(Self { diff --git a/crates/rune/src/ast/condition.rs b/crates/rune/src/ast/condition.rs index 8ddb3f15c..3c91e7b7f 100644 --- a/crates/rune/src/ast/condition.rs +++ b/crates/rune/src/ast/condition.rs @@ -12,7 +12,7 @@ fn ast_parse() { /// /// * `true`. /// * `let Some() = `. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum Condition { /// A regular expression. diff --git a/crates/rune/src/ast/expr.rs b/crates/rune/src/ast/expr.rs index 3afb2d48b..e85fa441e 100644 --- a/crates/rune/src/ast/expr.rs +++ b/crates/rune/src/ast/expr.rs @@ -107,7 +107,7 @@ impl ops::Deref for Callable { } /// A rune expression. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum Expr { /// An path expression. @@ -562,7 +562,7 @@ fn chain(p: &mut Parser<'_>, mut expr: Expr, callable: Callable) -> Result K!['['] if is_callable => { expr = Expr::Index(ast::ExprIndex { attributes: expr.take_attributes(), - target: Box::new(expr), + target: Box::try_new(expr)?, open: p.parse()?, index: p.parse()?, close: p.parse()?, @@ -575,14 +575,14 @@ fn chain(p: &mut Parser<'_>, mut expr: Expr, callable: Callable) -> Result expr = Expr::Call(ast::ExprCall { id: Default::default(), attributes: expr.take_attributes(), - expr: Box::new(expr), + expr: Box::try_new(expr)?, args, }); } K![?] => { expr = Expr::Try(ast::ExprTry { attributes: expr.take_attributes(), - expr: Box::new(expr), + expr: Box::try_new(expr)?, try_token: p.parse()?, }); } @@ -592,9 +592,9 @@ fn chain(p: &mut Parser<'_>, mut expr: Expr, callable: Callable) -> Result expr = Expr::Assign(ast::ExprAssign { attributes: expr.take_attributes(), - lhs: Box::new(expr), + lhs: Box::try_new(expr)?, eq, - rhs: Box::new(rhs), + rhs: Box::try_new(rhs)?, }); } K![.] => { @@ -603,7 +603,7 @@ fn chain(p: &mut Parser<'_>, mut expr: Expr, callable: Callable) -> Result K![await] => { expr = Expr::Await(ast::ExprAwait { attributes: expr.take_attributes(), - expr: Box::new(expr), + expr: Box::try_new(expr)?, dot: p.parse()?, await_token: p.parse()?, }); @@ -612,7 +612,7 @@ fn chain(p: &mut Parser<'_>, mut expr: Expr, callable: Callable) -> Result K![ident] => { expr = Expr::FieldAccess(ast::ExprFieldAccess { attributes: expr.take_attributes(), - expr: Box::new(expr), + expr: Box::try_new(expr)?, dot: p.parse()?, expr_field: ast::ExprField::Path(p.parse()?), }); @@ -621,7 +621,7 @@ fn chain(p: &mut Parser<'_>, mut expr: Expr, callable: Callable) -> Result K![number] => { expr = Expr::FieldAccess(ast::ExprFieldAccess { attributes: expr.take_attributes(), - expr: Box::new(expr), + expr: Box::try_new(expr)?, dot: p.parse()?, expr_field: ast::ExprField::LitNumber(p.parse()?), }); @@ -660,7 +660,7 @@ fn binary( lhs = range( p, lhs.take_attributes(), - Some(Box::new(lhs)), + Some(Box::try_new(lhs)?), ast::ExprRangeLimits::HalfOpen(token), eager_brace, )?; @@ -671,7 +671,7 @@ fn binary( lhs = range( p, lhs.take_attributes(), - Some(Box::new(lhs)), + Some(Box::try_new(lhs)?), ast::ExprRangeLimits::Closed(token), eager_brace, )?; @@ -681,7 +681,7 @@ fn binary( _ => (), } - let mut rhs = primary(p, &mut vec![], eager_brace, CALLABLE)?; + let mut rhs = primary(p, &mut Vec::new(), eager_brace, CALLABLE)?; lookahead = ast::BinOp::from_peeker(p.peeker()); while let Some(next) = lookahead { @@ -708,9 +708,9 @@ fn binary( lhs = Expr::Binary(ast::ExprBinary { attributes: lhs.take_attributes(), - lhs: Box::new(lhs), + lhs: Box::try_new(lhs)?, op, - rhs: Box::new(rhs), + rhs: Box::try_new(rhs)?, }); } @@ -726,12 +726,12 @@ fn range( eager_brace: EagerBrace, ) -> Result { let to = if Expr::peek_with_brace(p.peeker(), eager_brace) { - Some(Box::new(Expr::parse_with( + Some(Box::try_new(Expr::parse_with( p, eager_brace, EAGER_BINARY, CALLABLE, - )?)) + )?)?) } else { None }; @@ -753,7 +753,7 @@ fn empty_group(p: &mut Parser<'_>, attributes: Vec) -> Result, attributes: Vec) -> Result.await`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprAwait { /// Attributes associated with expression. diff --git a/crates/rune/src/ast/expr_binary.rs b/crates/rune/src/ast/expr_binary.rs index 159b274b6..b411fe9eb 100644 --- a/crates/rune/src/ast/expr_binary.rs +++ b/crates/rune/src/ast/expr_binary.rs @@ -13,7 +13,7 @@ fn ast_parse() { /// A binary expression. /// /// * ` `. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprBinary { /// Attributes associated with the binary expression. @@ -30,7 +30,8 @@ pub struct ExprBinary { expr_parse!(Binary, ExprBinary, "binary expression"); /// A binary operation. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ToTokens, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Hash, ToTokens, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub enum BinOp { /// Addition `a + b`. diff --git a/crates/rune/src/ast/expr_block.rs b/crates/rune/src/ast/expr_block.rs index 76167efcb..f919f52c1 100644 --- a/crates/rune/src/ast/expr_block.rs +++ b/crates/rune/src/ast/expr_block.rs @@ -26,7 +26,7 @@ fn ast_parse() { /// * ``. /// * `async `. /// * `const `. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprBlock { diff --git a/crates/rune/src/ast/expr_break.rs b/crates/rune/src/ast/expr_break.rs index 86744aec9..633f2cdae 100644 --- a/crates/rune/src/ast/expr_break.rs +++ b/crates/rune/src/ast/expr_break.rs @@ -12,7 +12,7 @@ fn ast_parse() { /// A break expression. /// /// * `break [expr]`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprBreak { diff --git a/crates/rune/src/ast/expr_call.rs b/crates/rune/src/ast/expr_call.rs index 8bd3e281c..af2bb9543 100644 --- a/crates/rune/src/ast/expr_call.rs +++ b/crates/rune/src/ast/expr_call.rs @@ -11,7 +11,7 @@ fn ast_parse() { /// A call expression. /// /// * `()`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned, Opaque)] #[non_exhaustive] pub struct ExprCall { /// Opaque identifier related with call. diff --git a/crates/rune/src/ast/expr_closure.rs b/crates/rune/src/ast/expr_closure.rs index 0c33cf822..e655b8a9c 100644 --- a/crates/rune/src/ast/expr_closure.rs +++ b/crates/rune/src/ast/expr_closure.rs @@ -21,7 +21,7 @@ fn ast_parse() { /// /// * `|| `. /// * `async || `. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprClosure { @@ -57,7 +57,7 @@ impl ExprClosure { expr_parse!(Closure, ExprClosure, "closure expression"); /// Representation of closure arguments. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens)] #[non_exhaustive] pub enum ExprClosureArgs { /// Closure has no arguments. @@ -116,7 +116,7 @@ impl Parse for ExprClosureArgs { let comma = p.parse::>()?; let is_end = comma.is_none(); - args.push((arg, comma)); + args.try_push((arg, comma))?; if is_end { break; diff --git a/crates/rune/src/ast/expr_continue.rs b/crates/rune/src/ast/expr_continue.rs index bf2c51d21..597f4c7a4 100644 --- a/crates/rune/src/ast/expr_continue.rs +++ b/crates/rune/src/ast/expr_continue.rs @@ -11,7 +11,7 @@ fn ast_parse() { /// A `continue` statement. /// /// * `continue [label]`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprContinue { diff --git a/crates/rune/src/ast/expr_empty.rs b/crates/rune/src/ast/expr_empty.rs index 9c86dedf7..6a75e3774 100644 --- a/crates/rune/src/ast/expr_empty.rs +++ b/crates/rune/src/ast/expr_empty.rs @@ -4,7 +4,7 @@ use crate::ast::prelude::*; /// /// These groups are only produced during internal desugaring. Most notably /// through the use of template literals. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprEmpty { /// Attributes associated with expression. diff --git a/crates/rune/src/ast/expr_field_access.rs b/crates/rune/src/ast/expr_field_access.rs index ff2d54313..e99637142 100644 --- a/crates/rune/src/ast/expr_field_access.rs +++ b/crates/rune/src/ast/expr_field_access.rs @@ -14,7 +14,7 @@ fn ast_parse() { /// A field access. /// /// * `.`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprFieldAccess { /// Attributes associated with expression. @@ -31,7 +31,7 @@ pub struct ExprFieldAccess { expr_parse!(FieldAccess, ExprFieldAccess, "field access expression"); /// The field being accessed. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum ExprField { /// An identifier. diff --git a/crates/rune/src/ast/expr_for.rs b/crates/rune/src/ast/expr_for.rs index 08dcc5c45..262fca090 100644 --- a/crates/rune/src/ast/expr_for.rs +++ b/crates/rune/src/ast/expr_for.rs @@ -13,7 +13,7 @@ fn ast_parse() { /// A `for` loop over an iterator. /// /// * `for in `. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprFor { /// The attributes of the `for` loop @@ -48,7 +48,7 @@ impl ExprFor { for_token: parser.parse()?, binding: parser.parse()?, in_: parser.parse()?, - iter: Box::new(ast::Expr::parse_without_eager_brace(parser)?), + iter: Box::try_new(ast::Expr::parse_without_eager_brace(parser)?)?, body: parser.parse()?, }) } diff --git a/crates/rune/src/ast/expr_group.rs b/crates/rune/src/ast/expr_group.rs index f51629bf4..f6c609335 100644 --- a/crates/rune/src/ast/expr_group.rs +++ b/crates/rune/src/ast/expr_group.rs @@ -11,7 +11,7 @@ fn ast_parse() { /// A prioritized expression group. /// /// * `()`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprGroup { /// Attributes associated with expression. diff --git a/crates/rune/src/ast/expr_if.rs b/crates/rune/src/ast/expr_if.rs index c2f56a000..419378688 100644 --- a/crates/rune/src/ast/expr_if.rs +++ b/crates/rune/src/ast/expr_if.rs @@ -14,7 +14,7 @@ fn ast_parse() { /// A conditional `if` expression. /// /// * `if cond { true } else { false }`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprIf { @@ -38,7 +38,7 @@ pub struct ExprIf { expr_parse!(If, ExprIf, "if expression"); /// An else branch of an if expression. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Parse, Spanned)] #[non_exhaustive] pub struct ExprElseIf { /// The `else` token. @@ -58,7 +58,7 @@ impl Peek for ExprElseIf { } /// An else branch of an if expression. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Parse, Spanned)] #[non_exhaustive] pub struct ExprElse { /// The `else` token. diff --git a/crates/rune/src/ast/expr_index.rs b/crates/rune/src/ast/expr_index.rs index 184475cb1..2a2c28c31 100644 --- a/crates/rune/src/ast/expr_index.rs +++ b/crates/rune/src/ast/expr_index.rs @@ -11,7 +11,7 @@ fn ast_parse() { /// An index get operation. /// /// * `[]`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprIndex { /// Attributes associated with expression. diff --git a/crates/rune/src/ast/expr_let.rs b/crates/rune/src/ast/expr_let.rs index 462c7c7f9..3976e1860 100644 --- a/crates/rune/src/ast/expr_let.rs +++ b/crates/rune/src/ast/expr_let.rs @@ -11,7 +11,7 @@ fn ast_parse() { /// A let expression. /// /// * `let = ` -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprLet { /// The attributes for the let expression @@ -42,19 +42,19 @@ impl ExprLet { mut_token: parser.parse()?, pat: parser.parse()?, eq: parser.parse()?, - expr: Box::new(ast::Expr::parse_without_eager_brace(parser)?), + expr: Box::try_new(ast::Expr::parse_without_eager_brace(parser)?)?, }) } /// Parse a let expression without eager bracing. pub(crate) fn parse_without_eager_brace(parser: &mut Parser) -> Result { Ok(Self { - attributes: vec![], + attributes: Vec::new(), let_token: parser.parse()?, mut_token: parser.parse()?, pat: parser.parse()?, eq: parser.parse()?, - expr: Box::new(ast::Expr::parse_without_eager_brace(parser)?), + expr: Box::try_new(ast::Expr::parse_without_eager_brace(parser)?)?, }) } } diff --git a/crates/rune/src/ast/expr_lit.rs b/crates/rune/src/ast/expr_lit.rs index 8d3c18e8c..e5cb7cd58 100644 --- a/crates/rune/src/ast/expr_lit.rs +++ b/crates/rune/src/ast/expr_lit.rs @@ -11,7 +11,7 @@ fn ast_parse() { /// A literal expression. With the addition of being able to receive attributes, /// this is identical to [ast::Lit]. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprLit { diff --git a/crates/rune/src/ast/expr_loop.rs b/crates/rune/src/ast/expr_loop.rs index 674e5c984..9f0f32856 100644 --- a/crates/rune/src/ast/expr_loop.rs +++ b/crates/rune/src/ast/expr_loop.rs @@ -13,7 +13,7 @@ fn ast_parse() { /// A `loop` expression. /// /// * `loop { ... }`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprLoop { diff --git a/crates/rune/src/ast/expr_match.rs b/crates/rune/src/ast/expr_match.rs index fa47e091c..97f780b2b 100644 --- a/crates/rune/src/ast/expr_match.rs +++ b/crates/rune/src/ast/expr_match.rs @@ -14,7 +14,7 @@ fn ast_parse() { /// A match expression. /// /// * `match { [arm]* }`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprMatch { /// The attributes for the match expression @@ -50,7 +50,7 @@ impl ExprMatch { let branch = parser.parse::()?; let comma = parser.parse::>()?; let is_end = ast::utils::is_block_end(&branch.body, comma.as_ref()); - branches.push((branch, comma)); + branches.try_push((branch, comma))?; if is_end { break; @@ -62,7 +62,7 @@ impl ExprMatch { Ok(ExprMatch { attributes, match_, - expr: Box::new(expr), + expr: Box::try_new(expr)?, open, branches, close, @@ -73,7 +73,7 @@ impl ExprMatch { expr_parse!(Match, ExprMatch, "match expression"); /// A match branch. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Parse, Spanned)] #[non_exhaustive] pub struct ExprMatchBranch { /// The pattern to match. diff --git a/crates/rune/src/ast/expr_object.rs b/crates/rune/src/ast/expr_object.rs index f182d2988..22d110df2 100644 --- a/crates/rune/src/ast/expr_object.rs +++ b/crates/rune/src/ast/expr_object.rs @@ -1,5 +1,4 @@ -use crate::no_std::borrow::Cow; - +use crate::alloc::borrow::Cow; use crate::ast::prelude::*; #[test] @@ -22,7 +21,7 @@ fn ast_parse() { /// /// * `#{ [field]* }`. /// * `Object { [field]* }`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprObject { /// Attributes associated with object. @@ -46,7 +45,7 @@ impl Peek for ExprObject { } /// A literal object identifier. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum ObjectIdent { /// An anonymous object. @@ -65,7 +64,7 @@ impl Parse for ObjectIdent { } /// A single field assignment in an object expression. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct FieldAssign { /// The key of the field. @@ -92,7 +91,7 @@ impl Parse for FieldAssign { } /// Possible literal object keys. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum ObjectKey { /// A literal string (with escapes). diff --git a/crates/rune/src/ast/expr_range.rs b/crates/rune/src/ast/expr_range.rs index 18948d8bb..e77661ee9 100644 --- a/crates/rune/src/ast/expr_range.rs +++ b/crates/rune/src/ast/expr_range.rs @@ -12,7 +12,7 @@ fn ast_parse() { /// A range expression. /// /// * `a .. b` or `a ..= b`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprRange { /// Attributes associated with the assign expression. @@ -29,7 +29,7 @@ pub struct ExprRange { } /// The limits of the specified range. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum ExprRangeLimits { /// Half-open range expression. diff --git a/crates/rune/src/ast/expr_return.rs b/crates/rune/src/ast/expr_return.rs index 084ed76fd..6e4d821f6 100644 --- a/crates/rune/src/ast/expr_return.rs +++ b/crates/rune/src/ast/expr_return.rs @@ -12,7 +12,7 @@ fn ast_parse() { /// A return expression. /// /// * `return [expr]`. -#[derive(Debug, Clone, Parse, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, Parse, PartialEq, Eq, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprReturn { diff --git a/crates/rune/src/ast/expr_select.rs b/crates/rune/src/ast/expr_select.rs index 11d6c6459..c85eac131 100644 --- a/crates/rune/src/ast/expr_select.rs +++ b/crates/rune/src/ast/expr_select.rs @@ -33,7 +33,7 @@ fn ast_parse() { /// A `select` expression that selects over a collection of futures. /// /// * `select { [arm]* }`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprSelect { /// The attributes of the `select` @@ -65,7 +65,7 @@ impl ExprSelect { let branch = ExprSelectBranch::parse(p)?; let comma = p.parse::>()?; let is_end = ast::utils::is_block_end(branch.expr(), comma.as_ref()); - branches.push((branch, comma)); + branches.try_push((branch, comma))?; if is_end { break; @@ -87,7 +87,7 @@ impl ExprSelect { expr_parse!(Select, ExprSelect, "select expression"); /// A single selection branch. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] #[allow(clippy::large_enum_variant)] pub enum ExprSelectBranch { @@ -118,7 +118,7 @@ impl Parse for ExprSelectBranch { } /// A single selection branch. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Parse, Spanned)] #[non_exhaustive] pub struct ExprSelectPatBranch { /// The identifier to bind the result to. @@ -134,7 +134,7 @@ pub struct ExprSelectPatBranch { } /// A single selection branch. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Parse, Spanned)] #[non_exhaustive] pub struct ExprDefaultBranch { /// The `default` keyword. diff --git a/crates/rune/src/ast/expr_try.rs b/crates/rune/src/ast/expr_try.rs index dfde2c132..559651c38 100644 --- a/crates/rune/src/ast/expr_try.rs +++ b/crates/rune/src/ast/expr_try.rs @@ -11,7 +11,7 @@ fn ast_parse() { /// A try expression. /// /// * `?`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprTry { /// Attributes associated with expression. diff --git a/crates/rune/src/ast/expr_tuple.rs b/crates/rune/src/ast/expr_tuple.rs index b727b1dd1..2575fc53b 100644 --- a/crates/rune/src/ast/expr_tuple.rs +++ b/crates/rune/src/ast/expr_tuple.rs @@ -14,7 +14,7 @@ fn ast_parse() { /// An expression to construct a literal tuple. /// /// * `(,*)`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprTuple { /// Attributes associated with tuple. diff --git a/crates/rune/src/ast/expr_unary.rs b/crates/rune/src/ast/expr_unary.rs index 242527ed5..bdaeb141f 100644 --- a/crates/rune/src/ast/expr_unary.rs +++ b/crates/rune/src/ast/expr_unary.rs @@ -22,7 +22,7 @@ fn ast_parse() { } /// A unary expression. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprUnary { /// Attributes associated with expression. @@ -44,12 +44,12 @@ impl ExprUnary { Ok(Self { attributes, op: p.parse()?, - expr: Box::new(ast::Expr::parse_with( + expr: Box::try_new(ast::Expr::parse_with( p, eager_brace, ast::expr::NOT_EAGER_BINARY, ast::expr::CALLABLE, - )?), + )?)?, }) } } @@ -57,7 +57,8 @@ impl ExprUnary { expr_parse!(Unary, ExprUnary, "try expression"); /// A unary operation. -#[derive(Debug, Clone, Copy, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, ToTokens, Spanned)] +#[try_clone(copy)] pub enum UnOp { /// Not `!`. Not(ast::Bang), diff --git a/crates/rune/src/ast/expr_vec.rs b/crates/rune/src/ast/expr_vec.rs index 10492f52f..7fe6096ab 100644 --- a/crates/rune/src/ast/expr_vec.rs +++ b/crates/rune/src/ast/expr_vec.rs @@ -12,7 +12,7 @@ fn ast_parse() { /// A literal vector. /// /// * `[,*]` -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[non_exhaustive] pub struct ExprVec { /// Attributes associated with vector. diff --git a/crates/rune/src/ast/expr_while.rs b/crates/rune/src/ast/expr_while.rs index b3d3fb9b9..2a7007db7 100644 --- a/crates/rune/src/ast/expr_while.rs +++ b/crates/rune/src/ast/expr_while.rs @@ -12,7 +12,7 @@ fn ast_parse() { /// A `while` loop. /// /// * `while [expr] { ... }`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprWhile { diff --git a/crates/rune/src/ast/expr_yield.rs b/crates/rune/src/ast/expr_yield.rs index 52df1c26f..1b9a11820 100644 --- a/crates/rune/src/ast/expr_yield.rs +++ b/crates/rune/src/ast/expr_yield.rs @@ -12,7 +12,7 @@ fn ast_parse() { /// A `yield` expression to return a value from a generator. /// /// * `yield [expr]`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ExprYield { diff --git a/crates/rune/src/ast/fields.rs b/crates/rune/src/ast/fields.rs index 404641920..1b9643f9c 100644 --- a/crates/rune/src/ast/fields.rs +++ b/crates/rune/src/ast/fields.rs @@ -4,7 +4,7 @@ use core::slice; use crate::ast::prelude::*; /// An item body declaration. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, OptionSpanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, OptionSpanned)] #[non_exhaustive] pub enum Fields { /// A regular body. diff --git a/crates/rune/src/ast/file.rs b/crates/rune/src/ast/file.rs index 1027576ed..5ab0896f2 100644 --- a/crates/rune/src/ast/file.rs +++ b/crates/rune/src/ast/file.rs @@ -53,7 +53,7 @@ fn ast_parse() { } /// A rune file. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, OptionSpanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, OptionSpanned)] #[non_exhaustive] pub struct File { /// Top-level shebang. @@ -71,11 +71,11 @@ impl Parse for File { fn parse(p: &mut Parser<'_>) -> Result { let shebang = p.parse()?; - let mut attributes = vec![]; + let mut attributes = try_vec![]; // only allow outer attributes at the top of a file while p.peek::()? { - attributes.push(p.parse()?); + attributes.try_push(p.parse()?)?; } let mut items = Vec::new(); @@ -94,7 +94,7 @@ impl Parse for File { None }; - items.push((item, semi_colon)); + items.try_push((item, semi_colon))?; item_attributes = p.parse()?; item_visibility = p.parse()?; path = p.parse()?; @@ -118,7 +118,7 @@ impl Parse for File { } /// The shebang of a file. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, TryClone, PartialEq, Eq)] #[non_exhaustive] pub struct Shebang { /// The span of the shebang. @@ -154,7 +154,11 @@ impl Spanned for Shebang { } impl ToTokens for Shebang { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Shebang(self.source), diff --git a/crates/rune/src/ast/fn_arg.rs b/crates/rune/src/ast/fn_arg.rs index cd7180352..1c64e35df 100644 --- a/crates/rune/src/ast/fn_arg.rs +++ b/crates/rune/src/ast/fn_arg.rs @@ -10,7 +10,7 @@ fn ast_parse() { } /// A single argument in a closure. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum FnArg { /// The `self` parameter. diff --git a/crates/rune/src/ast/generated.rs b/crates/rune/src/ast/generated.rs index 46dec01fb..9cd0dc16f 100644 --- a/crates/rune/src/ast/generated.rs +++ b/crates/rune/src/ast/generated.rs @@ -1,3 +1,5 @@ +use crate as rune; +use crate::alloc::clone; use crate::ast; use crate::compile; use crate::macros; @@ -8,7 +10,8 @@ use core::fmt; /// DO NOT modify by hand! /// The `abstract` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Abstract { /// Associated span. @@ -49,16 +52,17 @@ impl macros::ToTokens for Abstract { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Abstract, - }); + }) } } /// The `alignof` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct AlignOf { /// Associated span. @@ -99,16 +103,17 @@ impl macros::ToTokens for AlignOf { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::AlignOf, - }); + }) } } /// `&`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Amp { /// Associated span. @@ -149,16 +154,17 @@ impl macros::ToTokens for Amp { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Amp, - }); + }) } } /// `&&`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct AmpAmp { /// Associated span. @@ -199,16 +205,17 @@ impl macros::ToTokens for AmpAmp { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::AmpAmp, - }); + }) } } /// `&=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct AmpEq { /// Associated span. @@ -249,16 +256,17 @@ impl macros::ToTokens for AmpEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::AmpEq, - }); + }) } } /// `->`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Arrow { /// Associated span. @@ -299,16 +307,17 @@ impl macros::ToTokens for Arrow { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Arrow, - }); + }) } } /// The `as` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct As { /// Associated span. @@ -349,16 +358,17 @@ impl macros::ToTokens for As { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::As, - }); + }) } } /// The `async` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Async { /// Associated span. @@ -399,16 +409,17 @@ impl macros::ToTokens for Async { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Async, - }); + }) } } /// `@`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct At { /// Associated span. @@ -449,16 +460,17 @@ impl macros::ToTokens for At { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::At, - }); + }) } } /// The `await` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Await { /// Associated span. @@ -499,16 +511,17 @@ impl macros::ToTokens for Await { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Await, - }); + }) } } /// `!`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Bang { /// Associated span. @@ -549,16 +562,17 @@ impl macros::ToTokens for Bang { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Bang, - }); + }) } } /// `!=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct BangEq { /// Associated span. @@ -599,16 +613,17 @@ impl macros::ToTokens for BangEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::BangEq, - }); + }) } } /// The `become` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Become { /// Associated span. @@ -649,16 +664,17 @@ impl macros::ToTokens for Become { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Become, - }); + }) } } /// The `break` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Break { /// Associated span. @@ -699,16 +715,17 @@ impl macros::ToTokens for Break { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Break, - }); + }) } } /// `^`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Caret { /// Associated span. @@ -749,16 +766,17 @@ impl macros::ToTokens for Caret { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Caret, - }); + }) } } /// `^=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct CaretEq { /// Associated span. @@ -799,16 +817,17 @@ impl macros::ToTokens for CaretEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::CaretEq, - }); + }) } } /// `:`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Colon { /// Associated span. @@ -849,16 +868,17 @@ impl macros::ToTokens for Colon { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Colon, - }); + }) } } /// `::`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct ColonColon { /// Associated span. @@ -899,16 +919,17 @@ impl macros::ToTokens for ColonColon { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::ColonColon, - }); + }) } } /// `,`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Comma { /// Associated span. @@ -949,16 +970,17 @@ impl macros::ToTokens for Comma { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Comma, - }); + }) } } /// The `const` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Const { /// Associated span. @@ -999,16 +1021,17 @@ impl macros::ToTokens for Const { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Const, - }); + }) } } /// The `continue` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Continue { /// Associated span. @@ -1049,16 +1072,17 @@ impl macros::ToTokens for Continue { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Continue, - }); + }) } } /// The `crate` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Crate { /// Associated span. @@ -1099,16 +1123,17 @@ impl macros::ToTokens for Crate { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Crate, - }); + }) } } /// `-`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Dash { /// Associated span. @@ -1149,16 +1174,17 @@ impl macros::ToTokens for Dash { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Dash, - }); + }) } } /// `-=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct DashEq { /// Associated span. @@ -1199,16 +1225,17 @@ impl macros::ToTokens for DashEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::DashEq, - }); + }) } } /// The `default` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Default { /// Associated span. @@ -1249,16 +1276,17 @@ impl macros::ToTokens for Default { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Default, - }); + }) } } /// `/`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Div { /// Associated span. @@ -1299,16 +1327,17 @@ impl macros::ToTokens for Div { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Div, - }); + }) } } /// The `do` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Do { /// Associated span. @@ -1349,16 +1378,17 @@ impl macros::ToTokens for Do { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Do, - }); + }) } } /// `$`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Dollar { /// Associated span. @@ -1399,16 +1429,17 @@ impl macros::ToTokens for Dollar { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Dollar, - }); + }) } } /// `.`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Dot { /// Associated span. @@ -1449,16 +1480,17 @@ impl macros::ToTokens for Dot { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Dot, - }); + }) } } /// `..`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct DotDot { /// Associated span. @@ -1499,16 +1531,17 @@ impl macros::ToTokens for DotDot { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::DotDot, - }); + }) } } /// `..=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct DotDotEq { /// Associated span. @@ -1549,16 +1582,17 @@ impl macros::ToTokens for DotDotEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::DotDotEq, - }); + }) } } /// The `else` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Else { /// Associated span. @@ -1599,16 +1633,17 @@ impl macros::ToTokens for Else { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Else, - }); + }) } } /// The `enum` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Enum { /// Associated span. @@ -1649,16 +1684,17 @@ impl macros::ToTokens for Enum { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Enum, - }); + }) } } /// `=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Eq { /// Associated span. @@ -1699,16 +1735,17 @@ impl macros::ToTokens for Eq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Eq, - }); + }) } } /// `==`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct EqEq { /// Associated span. @@ -1749,16 +1786,17 @@ impl macros::ToTokens for EqEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::EqEq, - }); + }) } } /// The `extern` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Extern { /// Associated span. @@ -1799,16 +1837,17 @@ impl macros::ToTokens for Extern { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Extern, - }); + }) } } /// The `false` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct False { /// Associated span. @@ -1849,16 +1888,17 @@ impl macros::ToTokens for False { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::False, - }); + }) } } /// The `final` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Final { /// Associated span. @@ -1899,16 +1939,17 @@ impl macros::ToTokens for Final { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Final, - }); + }) } } /// The `fn` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Fn { /// Associated span. @@ -1949,16 +1990,17 @@ impl macros::ToTokens for Fn { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Fn, - }); + }) } } /// The `for` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct For { /// Associated span. @@ -1999,16 +2041,17 @@ impl macros::ToTokens for For { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::For, - }); + }) } } /// `>`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Gt { /// Associated span. @@ -2049,16 +2092,17 @@ impl macros::ToTokens for Gt { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Gt, - }); + }) } } /// `>=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct GtEq { /// Associated span. @@ -2099,16 +2143,17 @@ impl macros::ToTokens for GtEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::GtEq, - }); + }) } } /// `>>`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct GtGt { /// Associated span. @@ -2149,16 +2194,17 @@ impl macros::ToTokens for GtGt { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::GtGt, - }); + }) } } /// `>>=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct GtGtEq { /// Associated span. @@ -2199,16 +2245,17 @@ impl macros::ToTokens for GtGtEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::GtGtEq, - }); + }) } } /// The `if` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct If { /// Associated span. @@ -2249,16 +2296,17 @@ impl macros::ToTokens for If { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::If, - }); + }) } } /// The `impl` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Impl { /// Associated span. @@ -2299,16 +2347,17 @@ impl macros::ToTokens for Impl { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Impl, - }); + }) } } /// The `in` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct In { /// Associated span. @@ -2349,16 +2398,17 @@ impl macros::ToTokens for In { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::In, - }); + }) } } /// The `is` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Is { /// Associated span. @@ -2399,16 +2449,17 @@ impl macros::ToTokens for Is { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Is, - }); + }) } } /// The `let` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Let { /// Associated span. @@ -2449,16 +2500,17 @@ impl macros::ToTokens for Let { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Let, - }); + }) } } /// The `loop` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Loop { /// Associated span. @@ -2499,16 +2551,17 @@ impl macros::ToTokens for Loop { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Loop, - }); + }) } } /// `<`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Lt { /// Associated span. @@ -2549,16 +2602,17 @@ impl macros::ToTokens for Lt { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Lt, - }); + }) } } /// `<=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct LtEq { /// Associated span. @@ -2599,16 +2653,17 @@ impl macros::ToTokens for LtEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::LtEq, - }); + }) } } /// `<<`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct LtLt { /// Associated span. @@ -2649,16 +2704,17 @@ impl macros::ToTokens for LtLt { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::LtLt, - }); + }) } } /// `<<=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct LtLtEq { /// Associated span. @@ -2699,16 +2755,17 @@ impl macros::ToTokens for LtLtEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::LtLtEq, - }); + }) } } /// The `macro` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Macro { /// Associated span. @@ -2749,16 +2806,17 @@ impl macros::ToTokens for Macro { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Macro, - }); + }) } } /// The `match` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Match { /// Associated span. @@ -2799,16 +2857,17 @@ impl macros::ToTokens for Match { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Match, - }); + }) } } /// The `mod` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Mod { /// Associated span. @@ -2849,16 +2908,17 @@ impl macros::ToTokens for Mod { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Mod, - }); + }) } } /// The `move` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Move { /// Associated span. @@ -2899,16 +2959,17 @@ impl macros::ToTokens for Move { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Move, - }); + }) } } /// The `mut` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Mut { /// Associated span. @@ -2949,16 +3010,17 @@ impl macros::ToTokens for Mut { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Mut, - }); + }) } } /// The `not` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Not { /// Associated span. @@ -2999,16 +3061,17 @@ impl macros::ToTokens for Not { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Not, - }); + }) } } /// The `offsetof` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct OffsetOf { /// Associated span. @@ -3049,16 +3112,17 @@ impl macros::ToTokens for OffsetOf { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::OffsetOf, - }); + }) } } /// The `override` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Override { /// Associated span. @@ -3099,16 +3163,17 @@ impl macros::ToTokens for Override { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Override, - }); + }) } } /// `%`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Perc { /// Associated span. @@ -3149,16 +3214,17 @@ impl macros::ToTokens for Perc { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Perc, - }); + }) } } /// `%=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct PercEq { /// Associated span. @@ -3199,16 +3265,17 @@ impl macros::ToTokens for PercEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::PercEq, - }); + }) } } /// `|`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Pipe { /// Associated span. @@ -3249,16 +3316,17 @@ impl macros::ToTokens for Pipe { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Pipe, - }); + }) } } /// |=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct PipeEq { /// Associated span. @@ -3299,16 +3367,17 @@ impl macros::ToTokens for PipeEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::PipeEq, - }); + }) } } /// `||`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct PipePipe { /// Associated span. @@ -3349,16 +3418,17 @@ impl macros::ToTokens for PipePipe { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::PipePipe, - }); + }) } } /// `+`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Plus { /// Associated span. @@ -3399,16 +3469,17 @@ impl macros::ToTokens for Plus { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Plus, - }); + }) } } /// `+=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct PlusEq { /// Associated span. @@ -3449,16 +3520,17 @@ impl macros::ToTokens for PlusEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::PlusEq, - }); + }) } } /// `#`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Pound { /// Associated span. @@ -3499,16 +3571,17 @@ impl macros::ToTokens for Pound { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Pound, - }); + }) } } /// The `priv` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Priv { /// Associated span. @@ -3549,16 +3622,17 @@ impl macros::ToTokens for Priv { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Priv, - }); + }) } } /// The `proc` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Proc { /// Associated span. @@ -3599,16 +3673,17 @@ impl macros::ToTokens for Proc { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Proc, - }); + }) } } /// The `pub` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Pub { /// Associated span. @@ -3649,16 +3724,17 @@ impl macros::ToTokens for Pub { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Pub, - }); + }) } } /// The `pure` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Pure { /// Associated span. @@ -3699,16 +3775,17 @@ impl macros::ToTokens for Pure { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Pure, - }); + }) } } /// `?`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct QuestionMark { /// Associated span. @@ -3749,16 +3826,17 @@ impl macros::ToTokens for QuestionMark { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::QuestionMark, - }); + }) } } /// The `ref` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Ref { /// Associated span. @@ -3799,16 +3877,17 @@ impl macros::ToTokens for Ref { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Ref, - }); + }) } } /// The `return` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Return { /// Associated span. @@ -3849,16 +3928,17 @@ impl macros::ToTokens for Return { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Return, - }); + }) } } /// `=>`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Rocket { /// Associated span. @@ -3899,16 +3979,17 @@ impl macros::ToTokens for Rocket { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Rocket, - }); + }) } } /// The `select` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Select { /// Associated span. @@ -3949,16 +4030,17 @@ impl macros::ToTokens for Select { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Select, - }); + }) } } /// The `Self` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct SelfType { /// Associated span. @@ -3999,16 +4081,17 @@ impl macros::ToTokens for SelfType { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::SelfType, - }); + }) } } /// The `self` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct SelfValue { /// Associated span. @@ -4049,16 +4132,17 @@ impl macros::ToTokens for SelfValue { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::SelfValue, - }); + }) } } /// `;`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct SemiColon { /// Associated span. @@ -4099,16 +4183,17 @@ impl macros::ToTokens for SemiColon { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::SemiColon, - }); + }) } } /// The `sizeof` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct SizeOf { /// Associated span. @@ -4149,16 +4234,17 @@ impl macros::ToTokens for SizeOf { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::SizeOf, - }); + }) } } /// `/=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct SlashEq { /// Associated span. @@ -4199,16 +4285,17 @@ impl macros::ToTokens for SlashEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::SlashEq, - }); + }) } } /// `*`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Star { /// Associated span. @@ -4249,16 +4336,17 @@ impl macros::ToTokens for Star { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Star, - }); + }) } } /// `*=`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct StarEq { /// Associated span. @@ -4299,16 +4387,17 @@ impl macros::ToTokens for StarEq { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::StarEq, - }); + }) } } /// The `static` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Static { /// Associated span. @@ -4349,16 +4438,17 @@ impl macros::ToTokens for Static { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Static, - }); + }) } } /// The `struct` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Struct { /// Associated span. @@ -4399,16 +4489,17 @@ impl macros::ToTokens for Struct { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Struct, - }); + }) } } /// The `super` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Super { /// Associated span. @@ -4449,16 +4540,17 @@ impl macros::ToTokens for Super { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Super, - }); + }) } } /// `~`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Tilde { /// Associated span. @@ -4499,16 +4591,17 @@ impl macros::ToTokens for Tilde { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Tilde, - }); + }) } } /// The `true` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct True { /// Associated span. @@ -4549,16 +4642,17 @@ impl macros::ToTokens for True { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::True, - }); + }) } } /// The `typeof` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct TypeOf { /// Associated span. @@ -4599,16 +4693,17 @@ impl macros::ToTokens for TypeOf { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::TypeOf, - }); + }) } } /// `_`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Underscore { /// Associated span. @@ -4649,16 +4744,17 @@ impl macros::ToTokens for Underscore { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Underscore, - }); + }) } } /// The `unsafe` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Unsafe { /// Associated span. @@ -4699,16 +4795,17 @@ impl macros::ToTokens for Unsafe { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Unsafe, - }); + }) } } /// The `use` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Use { /// Associated span. @@ -4749,16 +4846,17 @@ impl macros::ToTokens for Use { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Use, - }); + }) } } /// The `virtual` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Virtual { /// Associated span. @@ -4799,16 +4897,17 @@ impl macros::ToTokens for Virtual { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Virtual, - }); + }) } } /// The `while` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct While { /// Associated span. @@ -4849,16 +4948,17 @@ impl macros::ToTokens for While { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::While, - }); + }) } } /// The `yield` keyword. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Yield { /// Associated span. @@ -4899,11 +4999,11 @@ impl macros::ToTokens for Yield { &self, _: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Yield, - }); + }) } } @@ -5352,7 +5452,8 @@ macro_rules! K { } /// The kind of the token. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, clone::TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] pub enum Kind { /// En end-of-file marker. Eof, @@ -5768,11 +5869,11 @@ impl macros::ToTokens for Kind { &self, context: &mut macros::MacroContext<'_, '_, '_>, stream: &mut macros::TokenStream, - ) { + ) -> crate::alloc::Result<()> { stream.push(ast::Token { kind: *self, span: context.macro_span(), - }); + }) } } diff --git a/crates/rune/src/ast/grouped.rs b/crates/rune/src/ast/grouped.rs index 8aeec6b63..6b9f8dcde 100644 --- a/crates/rune/src/ast/grouped.rs +++ b/crates/rune/src/ast/grouped.rs @@ -1,7 +1,6 @@ use core::slice; -use crate::no_std::vec; - +use crate::alloc::vec; use crate::ast::prelude::*; #[test] @@ -29,7 +28,8 @@ fn ast_parse() { macro_rules! grouped { ($(#[$meta:meta])* $name:ident { $field:ident, $open:ty, $close:ty }) => { $(#[$meta])* - #[derive(Debug, Clone, PartialEq, Eq, ToTokens)] + #[derive(Debug, TryClone, PartialEq, Eq, ToTokens)] + #[try_clone(bound = {T: TryClone, S: TryClone})] #[non_exhaustive] pub struct $name { /// The open parenthesis. @@ -138,7 +138,7 @@ macro_rules! grouped { loop { let comma = parser.parse::>()?; let is_end = comma.is_none(); - $field.push((current, comma)); + $field.try_push((current, comma))?; if is_end || parser.peek::<$close>()? { break; @@ -171,7 +171,7 @@ macro_rules! grouped { let expr = parser.parse()?; let sep = parser.parse::>()?; let is_end = sep.is_none(); - $field.push((expr, sep)); + $field.try_push((expr, sep))?; if is_end { break; diff --git a/crates/rune/src/ast/ident.rs b/crates/rune/src/ast/ident.rs index 9a2e57b9b..7e0c992e8 100644 --- a/crates/rune/src/ast/ident.rs +++ b/crates/rune/src/ast/ident.rs @@ -18,14 +18,17 @@ fn ast_parse() { /// /// ``` /// use rune::ast; -/// use rune::macros::MacroContext; +/// use rune::macros; /// -/// MacroContext::test(|cx| { -/// let lit = cx.ident("foo"); -/// assert!(matches!(lit, ast::Ident { .. })) -/// }); +/// macros::test(|cx| { +/// let lit = cx.ident("foo")?; +/// assert!(matches!(lit, ast::Ident { .. })); +/// Ok(()) +/// })?; +/// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub struct Ident { /// The span of the identifier. @@ -89,10 +92,14 @@ impl<'a> Resolve<'a> for Ident { } impl ToTokens for Ident { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Ident(self.source), - }); + }) } } diff --git a/crates/rune/src/ast/item.rs b/crates/rune/src/ast/item.rs index 3c232e0d6..abd7b4242 100644 --- a/crates/rune/src/ast/item.rs +++ b/crates/rune/src/ast/item.rs @@ -5,7 +5,7 @@ use crate::ast::prelude::*; use super::Attribute; /// A declaration. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum Item { /// A use declaration. diff --git a/crates/rune/src/ast/item_const.rs b/crates/rune/src/ast/item_const.rs index 662eff73e..027b39e58 100644 --- a/crates/rune/src/ast/item_const.rs +++ b/crates/rune/src/ast/item_const.rs @@ -8,7 +8,7 @@ fn ast_parse() { } /// A const declaration. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ItemConst { diff --git a/crates/rune/src/ast/item_enum.rs b/crates/rune/src/ast/item_enum.rs index 965dbe7c5..a836cb26b 100644 --- a/crates/rune/src/ast/item_enum.rs +++ b/crates/rune/src/ast/item_enum.rs @@ -18,7 +18,7 @@ fn ast_parse() { } /// An enum item. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ItemEnum { @@ -39,7 +39,7 @@ pub struct ItemEnum { item_parse!(Enum, ItemEnum, "enum item"); /// An enum variant. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] #[non_exhaustive] pub struct ItemVariant { /// Opaque identifier of variant. diff --git a/crates/rune/src/ast/item_fn.rs b/crates/rune/src/ast/item_fn.rs index edb35e59f..aea664eca 100644 --- a/crates/rune/src/ast/item_fn.rs +++ b/crates/rune/src/ast/item_fn.rs @@ -39,7 +39,7 @@ fn ast_parse() { } /// A function item. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ItemFn { diff --git a/crates/rune/src/ast/item_impl.rs b/crates/rune/src/ast/item_impl.rs index b437a12d0..3e57c550d 100644 --- a/crates/rune/src/ast/item_impl.rs +++ b/crates/rune/src/ast/item_impl.rs @@ -13,7 +13,7 @@ fn ast_parse() { } /// An impl item. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct ItemImpl { /// The attributes of the `impl` block @@ -42,10 +42,10 @@ impl ItemImpl { let path = parser.parse()?; let open = parser.parse()?; - let mut functions = vec![]; + let mut functions = Vec::new(); while !parser.peek::()? { - functions.push(ast::ItemFn::parse(parser)?); + functions.try_push(ast::ItemFn::parse(parser)?)?; } let close = parser.parse()?; diff --git a/crates/rune/src/ast/item_mod.rs b/crates/rune/src/ast/item_mod.rs index 846d0142e..1d42bf977 100644 --- a/crates/rune/src/ast/item_mod.rs +++ b/crates/rune/src/ast/item_mod.rs @@ -15,7 +15,7 @@ fn ast_parse() { } /// A module item. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ItemMod { @@ -50,7 +50,7 @@ impl ItemMod { item_parse!(Mod, ItemMod, "mod item"); /// An item body. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum ItemModBody { /// An empty body terminated by a semicolon. @@ -69,7 +69,7 @@ impl Parse for ItemModBody { } /// A module declaration. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Parse, Spanned)] #[non_exhaustive] pub struct ItemInlineBody { /// The open brace. diff --git a/crates/rune/src/ast/item_struct.rs b/crates/rune/src/ast/item_struct.rs index 39e7a8e31..53b8bcaa4 100644 --- a/crates/rune/src/ast/item_struct.rs +++ b/crates/rune/src/ast/item_struct.rs @@ -27,7 +27,7 @@ fn ast_parse() { } /// A struct item. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ItemStruct { @@ -59,7 +59,7 @@ impl ItemStruct { item_parse!(Struct, ItemStruct, "struct item"); /// A field as part of a struct or a tuple body. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Parse, Spanned)] #[non_exhaustive] pub struct Field { /// Attributes associated with field. diff --git a/crates/rune/src/ast/item_use.rs b/crates/rune/src/ast/item_use.rs index 7f8654641..154155182 100644 --- a/crates/rune/src/ast/item_use.rs +++ b/crates/rune/src/ast/item_use.rs @@ -20,7 +20,7 @@ fn ast_parse() { /// A `use` item. /// /// * `use ` -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[rune(parse = "meta_only")] #[non_exhaustive] pub struct ItemUse { @@ -41,7 +41,7 @@ item_parse!(Use, ItemUse, "use item"); /// A single use declaration path. /// /// * `foo::bar::{baz::*, biz}`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)] #[non_exhaustive] pub struct ItemUsePath { /// Global prefix. @@ -58,7 +58,7 @@ pub struct ItemUsePath { } /// A use component. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum ItemUseSegment { /// A path segment. diff --git a/crates/rune/src/ast/label.rs b/crates/rune/src/ast/label.rs index dc935f505..c618e7d1d 100644 --- a/crates/rune/src/ast/label.rs +++ b/crates/rune/src/ast/label.rs @@ -15,14 +15,17 @@ fn ast_parse() { /// /// ``` /// use rune::ast; -/// use rune::macros::MacroContext; +/// use rune::macros; /// -/// MacroContext::test(|cx| { -/// let lit = cx.label("foo"); -/// assert!(matches!(lit, ast::Label { .. })) -/// }); +/// macros::test(|cx| { +/// let lit = cx.label("foo")?; +/// assert!(matches!(lit, ast::Label { .. })); +/// Ok(()) +/// })?; +/// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub struct Label { /// The token of the label. @@ -86,10 +89,14 @@ impl<'a> Resolve<'a> for Label { } impl ToTokens for Label { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Label(self.source), - }); + }) } } diff --git a/crates/rune/src/ast/lit.rs b/crates/rune/src/ast/lit.rs index 131fd69b2..7db832beb 100644 --- a/crates/rune/src/ast/lit.rs +++ b/crates/rune/src/ast/lit.rs @@ -25,14 +25,17 @@ fn ast_parse() { /// /// ``` /// use rune::ast; -/// use rune::macros::MacroContext; +/// use rune::macros; /// -/// MacroContext::test(|cx| { -/// let lit = cx.lit("hello world"); -/// assert!(matches!(lit, ast::Lit::Str(..))) -/// }); +/// macros::test(|cx| { +/// let lit = cx.lit("hello world")?; +/// assert!(matches!(lit, ast::Lit::Str(..))); +/// Ok(()) +/// })?; +/// # Ok::<_, rune::support::Error>(()) /// ``` -#[derive(Debug, Clone, Copy, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, ToTokens, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub enum Lit { /// A boolean literal diff --git a/crates/rune/src/ast/lit_bool.rs b/crates/rune/src/ast/lit_bool.rs index 17bcc8902..f53578df2 100644 --- a/crates/rune/src/ast/lit_bool.rs +++ b/crates/rune/src/ast/lit_bool.rs @@ -12,7 +12,8 @@ fn ast_parse() { /// /// * `true`. /// * `false`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub struct LitBool { /// The span corresponding to the literal. @@ -48,7 +49,11 @@ impl Peek for LitBool { } impl ToTokens for LitBool { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: if self.value { @@ -56,6 +61,6 @@ impl ToTokens for LitBool { } else { ast::Kind::False }, - }); + }) } } diff --git a/crates/rune/src/ast/lit_byte.rs b/crates/rune/src/ast/lit_byte.rs index 65b7095db..757acdea8 100644 --- a/crates/rune/src/ast/lit_byte.rs +++ b/crates/rune/src/ast/lit_byte.rs @@ -12,7 +12,8 @@ fn ast_parse() { } /// A byte literal. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub struct LitByte { /// The span corresponding to the literal. @@ -112,10 +113,14 @@ impl<'a> Resolve<'a> for LitByte { } impl ToTokens for LitByte { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Byte(self.source), - }); + }) } } diff --git a/crates/rune/src/ast/lit_byte_str.rs b/crates/rune/src/ast/lit_byte_str.rs index 3d94041ff..d819a07b1 100644 --- a/crates/rune/src/ast/lit_byte_str.rs +++ b/crates/rune/src/ast/lit_byte_str.rs @@ -1,5 +1,4 @@ -use crate::no_std::borrow::Cow; - +use crate::alloc::borrow::Cow; use crate::ast::prelude::*; #[test] @@ -13,7 +12,8 @@ fn ast_parse() { /// A string literal. /// /// * `"Hello World"`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub struct LitByteStr { /// The span corresponding to the literal. @@ -25,7 +25,7 @@ pub struct LitByteStr { impl LitByteStr { fn parse_escaped(&self, span: Span, source: &str) -> Result> { - let mut buffer = Vec::with_capacity(source.len()); + let mut buffer = Vec::try_with_capacity(source.len())?; let start = span.start.into_usize(); @@ -35,7 +35,7 @@ impl LitByteStr { .peekable(); while let Some((start, c)) = it.next() { - buffer.extend(match c { + buffer.try_extend(match c { '\\' => { match ast::unescape::parse_byte_escape( &mut it, @@ -52,7 +52,7 @@ impl LitByteStr { } } c => Some(c as u8), - }); + })?; } Ok(buffer) @@ -111,10 +111,14 @@ impl<'a> Resolve<'a> for LitByteStr { } impl ToTokens for LitByteStr { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::ByteStr(self.source), - }); + }) } } diff --git a/crates/rune/src/ast/lit_char.rs b/crates/rune/src/ast/lit_char.rs index f8b760e85..85cb2b616 100644 --- a/crates/rune/src/ast/lit_char.rs +++ b/crates/rune/src/ast/lit_char.rs @@ -12,7 +12,8 @@ fn ast_parse() { } /// A character literal. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub struct LitChar { /// The span corresponding to the literal. @@ -110,10 +111,14 @@ impl<'a> Resolve<'a> for LitChar { } impl ToTokens for LitChar { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Char(self.source), - }); + }) } } diff --git a/crates/rune/src/ast/lit_number.rs b/crates/rune/src/ast/lit_number.rs index 282614e5a..7c9eed46e 100644 --- a/crates/rune/src/ast/lit_number.rs +++ b/crates/rune/src/ast/lit_number.rs @@ -16,7 +16,8 @@ fn ast_parse() { /// /// * `42`. /// * `4.2e10`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub struct LitNumber { /// The span corresponding to the literal. @@ -51,9 +52,8 @@ impl<'a> Resolve<'a> for LitNumber { let span = self.span; let text = match self.source { - ast::NumberSource::Synthetic(id) => match cx.storage.get_number(id) { - Some(number) => return Ok(number.clone()), - None => { + ast::NumberSource::Synthetic(id) => { + let Some(number) = cx.storage.get_number(id) else { return Err(compile::Error::new( span, ErrorKind::BadSyntheticId { @@ -61,8 +61,10 @@ impl<'a> Resolve<'a> for LitNumber { id, }, )); - } - }, + }; + + return Ok((*number).try_clone()?); + } ast::NumberSource::Text(text) => text, }; @@ -121,10 +123,14 @@ impl<'a> Resolve<'a> for LitNumber { } impl ToTokens for LitNumber { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Number(self.source), - }); + }) } } diff --git a/crates/rune/src/ast/lit_str.rs b/crates/rune/src/ast/lit_str.rs index f616c8859..1da3ececf 100644 --- a/crates/rune/src/ast/lit_str.rs +++ b/crates/rune/src/ast/lit_str.rs @@ -1,5 +1,4 @@ -use crate::no_std::borrow::Cow; - +use crate::alloc::borrow::Cow; use crate::ast::prelude::*; #[test] @@ -14,7 +13,8 @@ fn ast_parse() { /// /// * `"Hello World"`. /// * `"Hello\nWorld"`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub struct LitStr { /// The span corresponding to the literal. @@ -86,7 +86,7 @@ impl LitStr { source: &str, with_template: ast::unescape::WithTemplate, ) -> Result { - let mut buffer = String::with_capacity(source.len()); + let mut buffer = String::try_with_capacity(source.len())?; let start = span.start.into_usize(); @@ -96,7 +96,7 @@ impl LitStr { .peekable(); while let Some((start, c)) = it.next() { - buffer.extend(match c { + buffer.try_extend(match c { '\\' => match ast::unescape::parse_char_escape( &mut it, with_template, @@ -112,7 +112,7 @@ impl LitStr { } }, c => Some(c), - }); + })?; } Ok(buffer) @@ -142,10 +142,14 @@ impl<'a> Resolve<'a> for LitStr { } impl ToTokens for LitStr { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { stream.push(ast::Token { span: self.span, kind: ast::Kind::Str(self.source), - }); + }) } } diff --git a/crates/rune/src/ast/local.rs b/crates/rune/src/ast/local.rs index 4dbf410c1..231e85eff 100644 --- a/crates/rune/src/ast/local.rs +++ b/crates/rune/src/ast/local.rs @@ -12,7 +12,7 @@ fn ast_parse() { /// A local variable declaration. /// /// * `let = ;` -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Parse, Spanned)] #[non_exhaustive] pub struct Local { /// The attributes for the let expression diff --git a/crates/rune/src/ast/macro_call.rs b/crates/rune/src/ast/macro_call.rs index ca83d1c12..442a3ff93 100644 --- a/crates/rune/src/ast/macro_call.rs +++ b/crates/rune/src/ast/macro_call.rs @@ -11,7 +11,7 @@ fn ast_parse() { /// A macro call. /// /// * `!()`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned, Opaque)] #[non_exhaustive] pub struct MacroCall { /// Opaque identifier for macro call. Use to store reference to internally @@ -97,7 +97,7 @@ impl MacroCall { _ => (), } - stream.push(token); + stream.try_push(token)?; } Ok(Self { diff --git a/crates/rune/src/ast/macro_utils.rs b/crates/rune/src/ast/macro_utils.rs index 0ba65a0b5..2fbf9fdf7 100644 --- a/crates/rune/src/ast/macro_utils.rs +++ b/crates/rune/src/ast/macro_utils.rs @@ -4,7 +4,8 @@ use super::Eq; /// An `= ...` e.g. inside an attribute `#[doc = ...]`. /// /// To get unparsed tokens use `EqValue`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Parse, Spanned)] +#[try_clone(bound = {T: TryClone})] pub struct EqValue { /// The `=` token. pub eq: Eq, @@ -13,7 +14,7 @@ pub struct EqValue { } /// Parses `[{( ... )}]` ensuring that the delimiter is balanced. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] pub struct Group { /// The opening delimiter. pub open: ast::Token, @@ -66,7 +67,7 @@ impl Parse for Group { _ => (), } - stream.push(token); + stream.try_push(token)?; } Ok(Self { diff --git a/crates/rune/src/ast/pat.rs b/crates/rune/src/ast/pat.rs index 56aff9ba4..e8edc5ef9 100644 --- a/crates/rune/src/ast/pat.rs +++ b/crates/rune/src/ast/pat.rs @@ -19,7 +19,7 @@ fn ast_parse() { } /// A pattern match. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum Pat { /// An ignored binding `_`. @@ -48,25 +48,25 @@ impl Parse for Pat { K![byte] => { return Ok(Self::Lit(PatLit { attributes, - expr: Box::new(ast::Expr::from_lit(ast::Lit::Byte(p.parse()?))), + expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Byte(p.parse()?)))?, })); } K![char] => { return Ok(Self::Lit(PatLit { attributes, - expr: Box::new(ast::Expr::from_lit(ast::Lit::Char(p.parse()?))), + expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Char(p.parse()?)))?, })); } K![bytestr] => { return Ok(Self::Lit(PatLit { attributes, - expr: Box::new(ast::Expr::from_lit(ast::Lit::ByteStr(p.parse()?))), + expr: Box::try_new(ast::Expr::from_lit(ast::Lit::ByteStr(p.parse()?)))?, })); } K![true] | K![false] => { return Ok(Self::Lit(PatLit { attributes, - expr: Box::new(ast::Expr::from_lit(ast::Lit::Bool(p.parse()?))), + expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Bool(p.parse()?)))?, })); } K![str] => { @@ -79,14 +79,14 @@ impl Parse for Pat { }), _ => Self::Lit(PatLit { attributes, - expr: Box::new(ast::Expr::from_lit(ast::Lit::Str(p.parse()?))), + expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Str(p.parse()?)))?, }), }); } K![number] => { return Ok(Self::Lit(PatLit { attributes, - expr: Box::new(ast::Expr::from_lit(ast::Lit::Number(p.parse()?))), + expr: Box::try_new(ast::Expr::from_lit(ast::Lit::Number(p.parse()?)))?, })); } K![..] => { @@ -125,7 +125,7 @@ impl Parse for Pat { if expr.is_lit() { return Ok(Self::Lit(PatLit { attributes, - expr: Box::new(expr), + expr: Box::try_new(expr)?, })); } } @@ -182,7 +182,7 @@ impl Peek for Pat { } /// A literal pattern. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct PatLit { /// Attributes associated with the pattern. @@ -193,7 +193,7 @@ pub struct PatLit { } /// The rest pattern `..` and associated attributes. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct PatRest { /// Attribute associated with the rest pattern. @@ -204,7 +204,7 @@ pub struct PatRest { } /// An array pattern. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct PatVec { /// Attributes associated with the vector pattern. @@ -215,7 +215,7 @@ pub struct PatVec { } /// A tuple pattern. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct PatTuple { /// Attributes associated with the object pattern. @@ -229,7 +229,7 @@ pub struct PatTuple { } /// An object pattern. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct PatObject { /// Attributes associated with the object pattern. @@ -242,7 +242,7 @@ pub struct PatObject { } /// An object item. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned, Parse)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned, Parse)] #[non_exhaustive] pub struct PatBinding { /// Attributes associate with the binding. @@ -257,7 +257,7 @@ pub struct PatBinding { } /// A path pattern. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct PatPath { /// Attributes associate with the path. @@ -268,7 +268,7 @@ pub struct PatPath { } /// An ignore pattern. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct PatIgnore { /// Attributes associate with the pattern. diff --git a/crates/rune/src/ast/path.rs b/crates/rune/src/ast/path.rs index 5a92f1f82..5a4549482 100644 --- a/crates/rune/src/ast/path.rs +++ b/crates/rune/src/ast/path.rs @@ -14,7 +14,7 @@ fn ast_parse() { } /// A path, where each element is separated by a `::`. -#[derive(Debug, Clone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] +#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned, Opaque)] #[non_exhaustive] pub struct Path { /// Opaque id associated with path. @@ -102,65 +102,66 @@ impl<'a> Resolve<'a> for Path { let mut buf = String::new(); if self.global.is_some() { - buf.push_str("::"); + buf.try_push_str("::")?; } match &self.first { PathSegment::SelfType(_) => { - buf.push_str("Self"); + buf.try_push_str("Self")?; } PathSegment::SelfValue(_) => { - buf.push_str("self"); + buf.try_push_str("self")?; } PathSegment::Ident(ident) => { - buf.push_str(ident.resolve(cx)?); + buf.try_push_str(ident.resolve(cx)?)?; } PathSegment::Crate(_) => { - buf.push_str("crate"); + buf.try_push_str("crate")?; } PathSegment::Super(_) => { - buf.push_str("super"); + buf.try_push_str("super")?; } PathSegment::Generics(_) => { - buf.push_str("<*>"); + buf.try_push_str("<*>")?; } } for (_, segment) in &self.rest { - buf.push_str("::"); + buf.try_push_str("::")?; match segment { PathSegment::SelfType(_) => { - buf.push_str("Self"); + buf.try_push_str("Self")?; } PathSegment::SelfValue(_) => { - buf.push_str("self"); + buf.try_push_str("self")?; } PathSegment::Ident(ident) => { - buf.push_str(ident.resolve(cx)?); + buf.try_push_str(ident.resolve(cx)?)?; } PathSegment::Crate(_) => { - buf.push_str("crate"); + buf.try_push_str("crate")?; } PathSegment::Super(_) => { - buf.push_str("super"); + buf.try_push_str("super")?; } PathSegment::Generics(_) => { - buf.push_str("<*>"); + buf.try_push_str("<*>")?; } } } if self.trailing.is_some() { - buf.push_str("::"); + buf.try_push_str("::")?; } - Ok(buf.into_boxed_str()) + Ok(buf.try_into_boxed_str()?) } } /// An identified path kind. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq)] +#[try_clone(copy)] #[non_exhaustive] pub enum PathKind<'a> { /// A path that is the `self` value. @@ -170,7 +171,7 @@ pub enum PathKind<'a> { } /// Part of a `::` separated path. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub enum PathSegment { /// A path segment that contains `Self`. @@ -235,7 +236,7 @@ impl Peek for PathSegment { } /// Used to parse an expression without supporting an immediate binary expression. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct PathSegmentExpr { /// The expression that makes up the path segment. diff --git a/crates/rune/src/ast/prelude.rs b/crates/rune/src/ast/prelude.rs index bc64cf53a..52e661e47 100644 --- a/crates/rune/src/ast/prelude.rs +++ b/crates/rune/src/ast/prelude.rs @@ -1,11 +1,12 @@ //! Prelude for ast elements. pub(crate) use crate as rune; +pub(crate) use crate::alloc::prelude::*; +pub(crate) use crate::alloc::{self, try_vec, Box, String, Vec}; pub(crate) use crate::ast; pub(crate) use crate::ast::{OptionSpanned, Span, Spanned}; pub(crate) use crate::compile::{self, ErrorKind}; pub(crate) use crate::macros::{MacroContext, SyntheticKind, ToTokens, TokenStream}; -pub(crate) use crate::no_std::prelude::*; pub(crate) use crate::parse::Opaque; pub(crate) use crate::parse::{ Expectation, Id, IntoExpectation, Parse, Parser, Peek, Peeker, Resolve, ResolveContext, diff --git a/crates/rune/src/ast/span.rs b/crates/rune/src/ast/span.rs index f081173a2..6e7695266 100644 --- a/crates/rune/src/ast/span.rs +++ b/crates/rune/src/ast/span.rs @@ -4,8 +4,11 @@ use core::ops; use serde::{Deserialize, Serialize}; +use crate::ast::prelude::*; + /// A span corresponding to a range in the source file being parsed. -#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Default, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] pub struct Span { /// The start of the span in bytes. pub start: ByteIndex, @@ -200,9 +203,12 @@ impl fmt::Debug for Span { } /// A single index in a [Span], like the start or ending index. -#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[derive( + Default, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, +)] #[repr(transparent)] #[serde(transparent)] +#[try_clone(copy)] pub struct ByteIndex(#[doc(hidden)] pub u32); impl ByteIndex { diff --git a/crates/rune/src/ast/spanned.rs b/crates/rune/src/ast/spanned.rs index bb8ade3b8..6ba410789 100644 --- a/crates/rune/src/ast/spanned.rs +++ b/crates/rune/src/ast/spanned.rs @@ -1,5 +1,6 @@ use crate::no_std::boxed::Box; +use crate::alloc; use crate::ast::Span; use crate::parse::{Id, NonZeroId}; @@ -65,6 +66,15 @@ where } } +impl Spanned for alloc::Box +where + T: Spanned, +{ + fn span(&self) -> Span { + Spanned::span(&**self) + } +} + impl Spanned for &T where T: ?Sized + Spanned, @@ -150,3 +160,12 @@ where OptionSpanned::option_span(&**self) } } + +impl OptionSpanned for alloc::Box +where + T: OptionSpanned, +{ + fn option_span(&self) -> Option { + OptionSpanned::option_span(&**self) + } +} diff --git a/crates/rune/src/ast/stmt.rs b/crates/rune/src/ast/stmt.rs index e75e41c29..5ef389c41 100644 --- a/crates/rune/src/ast/stmt.rs +++ b/crates/rune/src/ast/stmt.rs @@ -11,7 +11,7 @@ fn ast_parse() { } /// A statement within a block. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] #[allow(clippy::large_enum_variant)] pub enum Stmt { @@ -56,7 +56,7 @@ impl Parse for Stmt { } let stmt = if let K![let] = p.nth(0)? { - let local = Box::new(ast::Local::parse_with_meta(p, take(&mut attributes))?); + let local = Box::try_new(ast::Local::parse_with_meta(p, take(&mut attributes))?)?; Self::Local(local) } else { let expr = ast::Expr::parse_with_meta(p, &mut attributes, ast::expr::CALLABLE)?; @@ -77,7 +77,7 @@ impl Parse for Stmt { } /// Parsing an item or an expression. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, TryClone, PartialEq, Eq)] #[non_exhaustive] #[allow(clippy::large_enum_variant)] pub enum ItemOrExpr { @@ -131,7 +131,8 @@ impl Parse for ItemOrExpr { } /// Key used to stort a statement into its processing order. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[try_clone(copy)] #[non_exhaustive] pub enum StmtSortKey { /// USe statements, that should be processed first. @@ -147,7 +148,7 @@ pub enum StmtSortKey { /// These have special meaning since they indicate that whatever block or /// function they belong to should not evaluate to the value of the expression /// if it is the last expression in the block. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct StmtSemi { /// The expression that is considered to be semi-terminated. diff --git a/crates/rune/src/ast/token.rs b/crates/rune/src/ast/token.rs index 95f98d9c2..4d9e88383 100644 --- a/crates/rune/src/ast/token.rs +++ b/crates/rune/src/ast/token.rs @@ -2,6 +2,7 @@ use core::ascii; use core::fmt; use core::ops::Neg; +use crate::ast::prelude::*; use crate::ast::{Kind, Span, Spanned}; use crate::compile; use crate::macros::{MacroContext, SyntheticId, ToTokens, TokenStream}; @@ -9,7 +10,8 @@ use crate::parse::{Expectation, IntoExpectation, Parse, Parser, Peek}; use crate::SourceId; /// A single token encountered during parsing. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct Token { /// The span of the token. @@ -162,8 +164,12 @@ impl Peek for Token { } impl ToTokens for Token { - fn to_tokens(&self, _: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { - stream.push(*self); + fn to_tokens( + &self, + _: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { + stream.push(*self) } } @@ -180,17 +186,18 @@ impl IntoExpectation for Token { } /// The value of a number literal. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] #[non_exhaustive] pub enum NumberValue { /// A float literal number. Float(f64), /// An integer literal number. - Integer(num::BigInt), + Integer(#[try_clone(with = num::BigInt::clone)] num::BigInt), } /// The suffix of a number. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub enum NumberSuffix { /// The `i64` suffix. @@ -202,7 +209,7 @@ pub enum NumberSuffix { } /// A resolved number literal. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] #[non_exhaustive] pub struct Number { /// The parsed number value. @@ -304,7 +311,8 @@ impl fmt::Display for Number { } /// The kind of a number literal. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub enum NumberBase { /// A decimal number literal, like `3.14`. @@ -332,7 +340,8 @@ impl fmt::Display for NumberBase { /// /// This is necessary to synthesize identifiers in the lexer since there's not /// storage available, nor is the identifier reflected in the source. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub enum BuiltIn { /// `template`. @@ -367,7 +376,8 @@ impl fmt::Display for BuiltIn { } /// The kind of the identifier. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub enum LitSource { /// The identifier is from the source text. @@ -381,7 +391,8 @@ pub enum LitSource { /// The source of the literal string. This need to be treated separately from /// [LitSource] because it might encompass special things like quoting and /// escaping. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub enum StrSource { /// The literal string source is from the source text. @@ -391,7 +402,8 @@ pub enum StrSource { } /// Configuration for a literal string. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct StrText { /// The source of the text. @@ -403,7 +415,8 @@ pub struct StrText { } /// The source of a number. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub enum NumberSource { /// The number is from the source text (and need to be parsed while it's @@ -414,8 +427,10 @@ pub enum NumberSource { } /// The source of an item that implements Copy. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] +#[try_clone(bound = {T: TryClone})] pub enum CopySource where T: Copy, @@ -428,7 +443,8 @@ where } /// Configuration of a text number. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub struct NumberText { /// The source of the text. @@ -444,7 +460,8 @@ pub struct NumberText { } /// A delimiter, `{`, `{`, or `[`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[non_exhaustive] pub enum Delimiter { /// A parenthesis delimiter `(` and `)`. diff --git a/crates/rune/src/ast/vis.rs b/crates/rune/src/ast/vis.rs index 1b0f616ff..838f3ec48 100644 --- a/crates/rune/src/ast/vis.rs +++ b/crates/rune/src/ast/vis.rs @@ -41,7 +41,7 @@ fn ast_parse() { /// * `pub(super)`. /// * `pub(crate)`. /// * `pub(in some::module)`. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, OptionSpanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, OptionSpanned)] #[non_exhaustive] pub enum Visibility { /// An inherited visibility level, this usually means private. @@ -121,7 +121,7 @@ impl Parse for Visibility { } /// A `in path` restriction to visibility. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] pub struct VisibilityIn { /// The `in` keyword. @@ -131,8 +131,9 @@ pub struct VisibilityIn { } /// A restriction to visibility. -#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)] +#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)] #[non_exhaustive] +#[try_clone(bound = {T: TryClone})] pub struct VisibilityRestrict { /// `pub` keyword. pub pub_token: ast::generated::Pub, diff --git a/crates/rune/src/build.rs b/crates/rune/src/build.rs index 616dcd1b3..ec04aa2dd 100644 --- a/crates/rune/src/build.rs +++ b/crates/rune/src/build.rs @@ -2,8 +2,7 @@ use core::fmt; use core::marker::PhantomData; use core::mem::take; -use crate::no_std::prelude::*; - +use crate::alloc::{self, Vec}; use crate::ast::{Span, Spanned}; use crate::compile; use crate::compile::{ @@ -16,20 +15,41 @@ use crate::{Context, Diagnostics, SourceId, Sources}; /// Error raised when we failed to load sources. /// /// Look at the passed in [Diagnostics] instance for details. -#[derive(Debug)] +#[derive(Default, Debug)] #[non_exhaustive] -pub struct BuildError; +pub struct BuildError { + kind: BuildErrorKind, +} + +impl From for BuildError { + fn from(error: alloc::Error) -> Self { + Self { + kind: BuildErrorKind::AllocError(error), + } + } +} + +#[derive(Default, Debug)] +enum BuildErrorKind { + #[default] + FatalError, + AllocError(alloc::Error), +} impl fmt::Display for BuildError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Failed to build rune sources (see diagnostics for details)" - ) + match &self.kind { + BuildErrorKind::FatalError => write!( + f, + "Failed to build rune sources (see diagnostics for details)" + ), + BuildErrorKind::AllocError(error) => error.fmt(f), + } } } -impl crate::no_std::error::Error for BuildError {} +#[cfg(feature = "std")] +impl std::error::Error for BuildError {} /// Entry point to building [Sources] of Rune using the default unit storage. /// @@ -47,7 +67,7 @@ impl crate::no_std::error::Error for BuildError {} /// use std::sync::Arc; /// /// let context = Context::with_default_modules()?; -/// let runtime = Arc::new(context.runtime()); +/// let runtime = Arc::new(context.runtime()?); /// /// let mut sources = rune::Sources::new(); /// sources.insert(Source::new("entry", r#" @@ -71,7 +91,7 @@ impl crate::no_std::error::Error for BuildError {} /// let unit = result?; /// let unit = Arc::new(unit); /// let vm = Vm::new(runtime, unit); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` pub fn prepare(sources: &mut Sources) -> Build<'_, DefaultStorage> { prepare_with(sources) @@ -118,10 +138,16 @@ impl<'a> compile::CompileVisitor for CompileVisitorGroup<'a> { Ok(()) } - fn visit_meta(&mut self, location: &dyn Located, meta: compile::MetaRef<'_>) { + fn visit_meta( + &mut self, + location: &dyn Located, + meta: compile::MetaRef<'_>, + ) -> Result<(), MetaError> { for v in self.visitors.iter_mut() { - v.visit_meta(location, meta) + v.visit_meta(location, meta)?; } + + Ok(()) } fn visit_variable_use( @@ -129,16 +155,20 @@ impl<'a> compile::CompileVisitor for CompileVisitorGroup<'a> { source_id: SourceId, var_span: &dyn Spanned, span: &dyn Spanned, - ) { + ) -> Result<(), MetaError> { for v in self.visitors.iter_mut() { - v.visit_variable_use(source_id, var_span, span) + v.visit_variable_use(source_id, var_span, span)?; } + + Ok(()) } - fn visit_mod(&mut self, location: &dyn Located) { + fn visit_mod(&mut self, location: &dyn Located) -> Result<(), MetaError> { for v in self.visitors.iter_mut() { - v.visit_mod(location) + v.visit_mod(location)?; } + + Ok(()) } fn visit_doc_comment( @@ -147,10 +177,12 @@ impl<'a> compile::CompileVisitor for CompileVisitorGroup<'a> { item: &compile::Item, hash: crate::Hash, doc: &str, - ) { + ) -> Result<(), MetaError> { for v in self.visitors.iter_mut() { - v.visit_doc_comment(location, item, hash, doc) + v.visit_doc_comment(location, item, hash, doc)?; } + + Ok(()) } fn visit_field_doc_comment( @@ -160,10 +192,12 @@ impl<'a> compile::CompileVisitor for CompileVisitorGroup<'a> { hash: crate::Hash, field: &str, doc: &str, - ) { + ) -> Result<(), MetaError> { for v in self.visitors.iter_mut() { - v.visit_field_doc_comment(location, item, hash, field, doc); + v.visit_field_doc_comment(location, item, hash, field, doc)?; } + + Ok(()) } } @@ -200,9 +234,9 @@ impl<'a, S> Build<'a, S> { /// Like if you want to collect every function that is discovered in the /// project. #[inline] - pub fn with_visitor(mut self, visitor: &'a mut dyn CompileVisitor) -> Self { - self.visitors.push(visitor); - self + pub fn with_visitor(mut self, visitor: &'a mut dyn CompileVisitor) -> alloc::Result { + self.visitors.try_push(visitor)?; + Ok(self) } /// Modify the current [Build] to configure the given [SourceLoader]. @@ -233,7 +267,7 @@ impl<'a, S> Build<'a, S> { let mut unit = compile::UnitBuilder::default(); let prelude = if context.has_default_modules() { - compile::Prelude::with_default_prelude() + compile::Prelude::with_default_prelude()? } else { compile::Prelude::default() }; @@ -261,7 +295,9 @@ impl<'a, S> Build<'a, S> { let mut default_visitors; let visitors = match self.visitors.is_empty() { true => { - default_visitors = CompileVisitorGroup { visitors: vec![] }; + default_visitors = CompileVisitorGroup { + visitors: Vec::new(), + }; &mut default_visitors } false => { @@ -282,10 +318,10 @@ impl<'a, S> Build<'a, S> { } }; - let mut pool = Pool::default(); + let mut pool = Pool::new()?; let mut unit_storage = S::default(); - let result = compile::compile( + compile::compile( &mut unit, &prelude, self.sources, @@ -296,25 +332,25 @@ impl<'a, S> Build<'a, S> { source_loader, options, &mut unit_storage, - ); + )?; - if let Err(()) = result { - return Err(BuildError); + if diagnostics.has_error() { + return Err(BuildError::default()); } if options.link_checks { - unit.link(context, diagnostics); + unit.link(context, diagnostics)?; + } - if diagnostics.has_error() { - return Err(BuildError); - } + if diagnostics.has_error() { + return Err(BuildError::default()); } match unit.build(Span::empty(), unit_storage) { Ok(unit) => Ok(unit), Err(error) => { diagnostics.error(SourceId::empty(), error); - Err(BuildError) + Err(BuildError::default()) } } } diff --git a/crates/rune/src/cli.rs b/crates/rune/src/cli.rs index ef44f72de..4c43147bf 100644 --- a/crates/rune/src/cli.rs +++ b/crates/rune/src/cli.rs @@ -20,8 +20,11 @@ mod naming; use std::fmt; use std::io::{self, Write}; use std::path::{Path, PathBuf}; +use rust_alloc::string::String; +use rust_alloc::vec::Vec; -use crate::no_std::prelude::*; +use crate::alloc; +use crate::alloc::prelude::*; use crate::workspace::{self, WorkspaceFilter}; use anyhow::{bail, Context as _, Error, Result}; @@ -57,7 +60,7 @@ pub type ContextBuilder = dyn FnMut(ContextOptions<'_>) -> Result { - about: Option, + about: Option, context: Option<&'a mut ContextBuilder>, } @@ -80,7 +83,7 @@ impl<'a> Entry<'a> { /// .run(); ///``` pub fn about(mut self, about: impl fmt::Display) -> Self { - self.about = Some(about.to_string()); + self.about = Some(about.try_to_string().expect("Failed to format about string")); self } @@ -447,16 +450,16 @@ struct Config { /// Manifest root directory. manifest_root: Option, /// Immediate found paths. - found_paths: Vec, + found_paths: alloc::Vec, } impl Config { /// Construct build paths from configuration. - fn build_paths<'m>(&'m self, cmd: CommandSharedRef<'_>) -> Result>> { - let mut build_paths = Vec::new(); + fn build_paths<'m>(&'m self, cmd: CommandSharedRef<'_>) -> Result>> { + let mut build_paths = alloc::Vec::new(); if !self.found_paths.is_empty() { - build_paths.extend(self.found_paths.iter().map(|p| BuildPath::Path(p))); + build_paths.try_extend(self.found_paths.iter().map(|p| BuildPath::Path(p)))?; if !cmd.shared.workspace { return Ok(build_paths); @@ -465,25 +468,25 @@ impl Config { if let Some(bin) = cmd.find_bins() { for p in self.manifest.find_bins(bin)? { - build_paths.push(BuildPath::Package(p)); + build_paths.try_push(BuildPath::Package(p))?; } } if let Some(test) = cmd.find_tests() { for p in self.manifest.find_tests(test)? { - build_paths.push(BuildPath::Package(p)); + build_paths.try_push(BuildPath::Package(p))?; } } if let Some(example) = cmd.find_examples() { for p in self.manifest.find_examples(example)? { - build_paths.push(BuildPath::Package(p)); + build_paths.try_push(BuildPath::Package(p))?; } } if let Some(bench) = cmd.find_benches() { for p in self.manifest.find_benches(bench)? { - build_paths.push(BuildPath::Package(p)); + build_paths.try_push(BuildPath::Package(p))?; } } @@ -661,12 +664,12 @@ fn find_manifest() -> Option<(PathBuf, PathBuf)> { } fn populate_config(io: &mut Io<'_>, c: &mut Config, cmd: CommandSharedRef<'_>) -> Result<()> { - c.found_paths.extend( + c.found_paths.try_extend( cmd.shared .paths .iter() .map(|p| p.as_path().into()), - ); + )?; if !c.found_paths.is_empty() && !cmd.shared.workspace { return Ok(()); @@ -677,7 +680,7 @@ fn populate_config(io: &mut Io<'_>, c: &mut Config, cmd: CommandSharedRef<'_>) - let path = Path::new(file); if path.is_file() { - c.found_paths.push(path.into()); + c.found_paths.try_push(path.into())?; return Ok(()); } } @@ -696,7 +699,7 @@ fn populate_config(io: &mut Io<'_>, c: &mut Config, cmd: CommandSharedRef<'_>) - c.manifest_root = Some(manifest_root); let mut sources = crate::Sources::new(); - sources.insert(crate::Source::from_path(manifest_path)?); + sources.insert(crate::Source::from_path(manifest_path)?)?; let mut diagnostics = workspace::Diagnostics::new(); @@ -719,13 +722,13 @@ async fn main_with_out(io: &mut Io<'_>, entry: &mut Entry<'_>, mut args: Args) - let cmd = match &args.cmd { Some(cmd) => cmd, None => { - let commands = Command::ALL.into_iter().collect::>().join(", "); + let commands: alloc::String = Command::ALL.into_iter().try_join(", ")?; writeln!(io.stdout, "Expected a subcommand: {commands}")?; return Ok(ExitCode::Failure); } }; - let mut entrys = Vec::new(); + let mut entrys = alloc::Vec::new(); if let Some(cmd) = cmd.as_command_shared_ref() { populate_config(io, &mut c, cmd)?; @@ -739,8 +742,8 @@ async fn main_with_out(io: &mut Io<'_>, entry: &mut Entry<'_>, mut args: Args) - for build_path in build_paths { match build_path { BuildPath::Path(path) => { - for path in loader::recurse_paths(recursive, path.to_owned()) { - entrys.push(EntryPoint::Path(path?)); + for path in loader::recurse_paths(recursive, path.try_to_owned()?) { + entrys.try_push(EntryPoint::Path(path?))?; } } BuildPath::Package(p) => { @@ -754,7 +757,7 @@ async fn main_with_out(io: &mut Io<'_>, entry: &mut Entry<'_>, mut args: Args) - writeln!(o, " {} `{}` (from {})", p.found.kind, p.found.path.display(), p.package.name)?; } - entrys.push(EntryPoint::Package(p)); + entrys.try_push(EntryPoint::Package(p))?; } } } diff --git a/crates/rune/src/cli/benches.rs b/crates/rune/src/cli/benches.rs index 2c9a35696..13a3b6fb1 100644 --- a/crates/rune/src/cli/benches.rs +++ b/crates/rune/src/cli/benches.rs @@ -52,7 +52,7 @@ pub(super) async fn run( sources: &Sources, fns: &[(Hash, ItemBuf)], ) -> anyhow::Result { - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut vm = Vm::new(runtime, unit); if fns.is_empty() { diff --git a/crates/rune/src/cli/check.rs b/crates/rune/src/cli/check.rs index 5c9d1cd82..fe2d55676 100644 --- a/crates/rune/src/cli/check.rs +++ b/crates/rune/src/cli/check.rs @@ -50,7 +50,7 @@ pub(super) fn run( let mut sources = Sources::new(); - sources.insert(source); + sources.insert(source)?; let mut diagnostics = if shared.warnings || flags.warnings_are_errors { Diagnostics::new() @@ -65,7 +65,7 @@ pub(super) fn run( .with_context(&context) .with_diagnostics(&mut diagnostics) .with_options(options) - .with_visitor(&mut test_finder) + .with_visitor(&mut test_finder)? .with_source_loader(&mut source_loader) .build(); diff --git a/crates/rune/src/cli/doc.rs b/crates/rune/src/cli/doc.rs index b73e5879a..ce07a4f7e 100644 --- a/crates/rune/src/cli/doc.rs +++ b/crates/rune/src/cli/doc.rs @@ -80,12 +80,12 @@ where for e in entries { let name = naming.name(&e); - let item = ItemBuf::with_crate(&name); - let mut visitor = crate::doc::Visitor::new(item)?; + let item = ItemBuf::with_crate(&name)?; + let mut visitor = crate::doc::Visitor::new(&item)?; let mut sources = Sources::new(); let source = Source::from_path(e.path()) .with_context(|| e.path().display().to_string())?; - sources.insert(source); + sources.insert(source)?; let mut diagnostics = if shared.warnings || flags.warnings_are_errors { Diagnostics::new() @@ -99,7 +99,7 @@ where .with_context(&context) .with_diagnostics(&mut diagnostics) .with_options(options) - .with_visitor(&mut visitor) + .with_visitor(&mut visitor)? .with_source_loader(&mut source_loader) .build(); diff --git a/crates/rune/src/cli/format.rs b/crates/rune/src/cli/format.rs index 5c7122faa..83ec6429b 100644 --- a/crates/rune/src/cli/format.rs +++ b/crates/rune/src/cli/format.rs @@ -55,7 +55,7 @@ pub(super) fn run<'m, I>(io: &mut Io<'_>, entry: &mut Entry<'_>, c: &Config, ent }; let mut sources = Sources::new(); - sources.insert(Source::from_path(e.path()).with_context(|| e.path().display().to_string())?); + sources.insert(Source::from_path(e.path()).with_context(|| e.path().display().to_string())?)?; let _ = crate::prepare(&mut sources) .with_context(&context) diff --git a/crates/rune/src/cli/loader.rs b/crates/rune/src/cli/loader.rs index 499888b6c..d475e165f 100644 --- a/crates/rune/src/cli/loader.rs +++ b/crates/rune/src/cli/loader.rs @@ -4,11 +4,9 @@ use std::io; use std::path::PathBuf; use std::{path::Path, sync::Arc}; -use crate::no_std::collections::VecDeque; -use crate::no_std::prelude::*; - use anyhow::{anyhow, Context as _, Result}; +use crate::alloc::{VecDeque, Vec}; use crate::cli::{visitor, Io, SharedFlags}; use crate::compile::{FileSourceLoader, ItemBuf}; use crate::Diagnostics; @@ -35,7 +33,7 @@ pub(super) fn load( Source::from_path(path).with_context(|| anyhow!("cannot read file: {}", path.display()))?; let mut sources = Sources::new(); - sources.insert(source); + sources.insert(source)?; let use_cache = options.bytecode && should_cache_be_used(path, &bytecode_path)?; @@ -75,7 +73,7 @@ pub(super) fn load( .with_context(context) .with_diagnostics(&mut diagnostics) .with_options(options) - .with_visitor(&mut functions) + .with_visitor(&mut functions)? .with_source_loader(&mut source_loader) .build(); @@ -115,12 +113,12 @@ fn should_cache_be_used(source: &Path, cached: &Path) -> io::Result { pub(super) fn recurse_paths( recursive: bool, first: PathBuf, -) -> impl Iterator> { - let mut queue = VecDeque::with_capacity(1); - queue.push_back(first); +) -> impl Iterator> { + let mut queue = VecDeque::new(); + let mut first = Some(first); std::iter::from_fn(move || loop { - let path = queue.pop_front()?; + let path = first.take().or_else(|| queue.pop_front())?; if !recursive { return Some(Ok(path)); @@ -136,16 +134,18 @@ pub(super) fn recurse_paths( let d = match fs::read_dir(path) { Ok(d) => d, - Err(error) => return Some(Err(error)), + Err(error) => return Some(Err(anyhow::Error::from(error))), }; for e in d { let e = match e { Ok(e) => e, - Err(error) => return Some(Err(error)), + Err(error) => return Some(Err(anyhow::Error::from(error))), }; - queue.push_back(e.path()); + if let Err(error) = queue.try_push_back(e.path()) { + return Some(Err(anyhow::Error::from(error))); + } } }) } diff --git a/crates/rune/src/cli/run.rs b/crates/rune/src/cli/run.rs index e6f340060..e7704fbbe 100644 --- a/crates/rune/src/cli/run.rs +++ b/crates/rune/src/cli/run.rs @@ -195,7 +195,7 @@ pub(super) async fn run( } } - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let last = Instant::now(); diff --git a/crates/rune/src/cli/tests.rs b/crates/rune/src/cli/tests.rs index fb87ce0d1..1ddc75575 100644 --- a/crates/rune/src/cli/tests.rs +++ b/crates/rune/src/cli/tests.rs @@ -7,6 +7,7 @@ use crate::no_std::prelude::*; use anyhow::{bail, Result, Context}; use clap::Parser; +use crate::alloc::prelude::*; use crate::cli::{ExitCode, Io, CommandBase, AssetKind, Config, SharedFlags, EntryPoint, Entry, Options}; use crate::cli::visitor; use crate::cli::naming::Naming; @@ -97,14 +98,14 @@ where for e in entries { let name = naming.name(&e); - let item = ItemBuf::with_crate(&name); + let item = ItemBuf::with_crate(&name)?; let mut sources = Sources::new(); let source = Source::from_path(e.path()) .with_context(|| e.path().display().to_string())?; - sources.insert(source); + sources.insert(source)?; let mut diagnostics = if shared.warnings || flags.warnings_are_errors { Diagnostics::new() @@ -112,7 +113,7 @@ where Diagnostics::without_warnings() }; - let mut doc_visitor = crate::doc::Visitor::new(item)?; + let mut doc_visitor = crate::doc::Visitor::new(&item)?; let mut functions = visitor::FunctionVisitor::new(visitor::Attribute::Test); let mut source_loader = FileSourceLoader::new(); @@ -120,8 +121,8 @@ where .with_context(&context) .with_diagnostics(&mut diagnostics) .with_options(options) - .with_visitor(&mut doc_visitor) - .with_visitor(&mut functions) + .with_visitor(&mut doc_visitor)? + .with_visitor(&mut functions)? .with_source_loader(&mut source_loader) .build(); @@ -153,7 +154,7 @@ where let mut sources = Sources::new(); let source = Source::new(test.item.to_string(), &test.content); - sources.insert(source); + sources.insert(source)?; let mut diagnostics = if shared.warnings || flags.warnings_are_errors { Diagnostics::new() @@ -188,11 +189,11 @@ where bail!("Compiling source did not result in a function at offset 0"); }; - cases.push(TestCase::new(hash, test.item.clone(), unit.clone(), sources.clone(), test.params)); + cases.push(TestCase::new(hash, test.item.try_clone()?, unit.clone(), sources.clone(), test.params)); } } - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut failed = Vec::new(); let total = cases.len(); diff --git a/crates/rune/src/cli/visitor.rs b/crates/rune/src/cli/visitor.rs index 01860ef7c..58ed6ee38 100644 --- a/crates/rune/src/cli/visitor.rs +++ b/crates/rune/src/cli/visitor.rs @@ -1,5 +1,5 @@ -use crate::no_std::prelude::*; - +use crate::alloc::prelude::*; +use crate::alloc::Vec; use crate::compile::meta; use crate::compile::{MetaError, CompileVisitor, ItemBuf, MetaRef}; use crate::Hash; @@ -25,7 +25,7 @@ impl FunctionVisitor { pub(super) fn new(kind: Attribute) -> Self { Self { attribute: kind, - functions: Default::default(), + functions: Vec::default(), } } @@ -43,7 +43,7 @@ impl CompileVisitor for FunctionVisitor { _ => return Ok(()), }; - self.functions.push((type_hash, meta.item.to_owned())); + self.functions.try_push((type_hash, meta.item.try_to_owned()?))?; Ok(()) } } diff --git a/crates/rune/src/compile.rs b/crates/rune/src/compile.rs index 8e338d231..bef293217 100644 --- a/crates/rune/src/compile.rs +++ b/crates/rune/src/compile.rs @@ -14,6 +14,7 @@ pub(crate) use self::error::{ErrorKind, IrErrorKind}; mod compile_visitor; pub use self::compile_visitor::CompileVisitor; +#[cfg(feature = "std")] pub(crate) use self::compile_visitor::NoopCompileVisitor; pub(crate) mod context; diff --git a/crates/rune/src/compile/assembly.rs b/crates/rune/src/compile/assembly.rs index 3bc198c75..d6151d3c1 100644 --- a/crates/rune/src/compile/assembly.rs +++ b/crates/rune/src/compile/assembly.rs @@ -2,15 +2,17 @@ use core::fmt; -use crate::no_std::collections::{hash_map, HashMap}; -use crate::no_std::prelude::*; - +use crate as rune; +use crate::alloc::fmt::TryWrite; +use crate::alloc::prelude::*; +use crate::alloc::{hash_map, HashMap}; +use crate::alloc::{try_vec, String, Vec}; use crate::ast::{Span, Spanned}; use crate::compile::{self, Location}; use crate::runtime::{Inst, Label}; use crate::{Hash, SourceId}; -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) enum AssemblyInst { Jump { label: Label }, JumpIf { label: Label }, @@ -23,7 +25,7 @@ pub(crate) enum AssemblyInst { } /// Helper structure to build instructions and maintain certain invariants. -#[derive(Debug, Clone, Default)] +#[derive(Debug, TryClone, Default)] pub(crate) struct Assembly { /// The location that caused the assembly. location: Location, @@ -67,11 +69,11 @@ impl Assembly { hash_map::Entry::Occupied(e) => { let &mut (len, ref mut labels) = e.into_mut(); label.set_jump(len); - labels.push(label.clone()); + labels.try_push(label.try_clone()?)?; } hash_map::Entry::Vacant(e) => { label.set_jump(len); - e.insert((len, vec![label.clone()])); + e.try_insert((len, try_vec![label.try_clone()?]))?; } } @@ -79,90 +81,128 @@ impl Assembly { } /// Add a jump to the given label. - pub(crate) fn jump(&mut self, label: &Label, span: &dyn Spanned) { + pub(crate) fn jump(&mut self, label: &Label, span: &dyn Spanned) -> compile::Result<()> { self.inner_push( AssemblyInst::Jump { - label: label.clone(), + label: label.try_clone()?, }, span, - ); + )?; + + Ok(()) } /// Add a conditional jump to the given label. - pub(crate) fn jump_if(&mut self, label: &Label, span: &dyn Spanned) { + pub(crate) fn jump_if(&mut self, label: &Label, span: &dyn Spanned) -> compile::Result<()> { self.inner_push( AssemblyInst::JumpIf { - label: label.clone(), + label: label.try_clone()?, }, span, - ); + )?; + + Ok(()) } /// Add a conditional jump to the given label. Only pops the top of the /// stack if the jump is not executed. - pub(crate) fn jump_if_or_pop(&mut self, label: &Label, span: &dyn Spanned) { + pub(crate) fn jump_if_or_pop( + &mut self, + label: &Label, + span: &dyn Spanned, + ) -> compile::Result<()> { self.inner_push( AssemblyInst::JumpIfOrPop { - label: label.clone(), + label: label.try_clone()?, }, span, - ); + )?; + + Ok(()) } /// Add a conditional jump to the given label. Only pops the top of the /// stack if the jump is not executed. - pub(crate) fn jump_if_not_or_pop(&mut self, label: &Label, span: &dyn Spanned) { + pub(crate) fn jump_if_not_or_pop( + &mut self, + label: &Label, + span: &dyn Spanned, + ) -> compile::Result<()> { self.inner_push( AssemblyInst::JumpIfNotOrPop { - label: label.clone(), + label: label.try_clone()?, }, span, - ); + )?; + + Ok(()) } /// Add a conditional jump-if-branch instruction. - pub(crate) fn jump_if_branch(&mut self, branch: i64, label: &Label, span: &dyn Spanned) { + pub(crate) fn jump_if_branch( + &mut self, + branch: i64, + label: &Label, + span: &dyn Spanned, + ) -> compile::Result<()> { self.inner_push( AssemblyInst::JumpIfBranch { branch, - label: label.clone(), + label: label.try_clone()?, }, span, - ); + )?; + + Ok(()) } /// Add a pop-and-jump-if-not instruction to a label. - pub(crate) fn pop_and_jump_if_not(&mut self, count: usize, label: &Label, span: &dyn Spanned) { + pub(crate) fn pop_and_jump_if_not( + &mut self, + count: usize, + label: &Label, + span: &dyn Spanned, + ) -> compile::Result<()> { self.inner_push( AssemblyInst::PopAndJumpIfNot { count, - label: label.clone(), + label: label.try_clone()?, }, span, - ); + )?; + + Ok(()) } /// Add an instruction that advanced an iterator. - pub(crate) fn iter_next(&mut self, offset: usize, label: &Label, span: &dyn Spanned) { + pub(crate) fn iter_next( + &mut self, + offset: usize, + label: &Label, + span: &dyn Spanned, + ) -> compile::Result<()> { self.inner_push( AssemblyInst::IterNext { offset, - label: label.clone(), + label: label.try_clone()?, }, span, - ); + )?; + + Ok(()) } /// Push a raw instruction. - pub(crate) fn push(&mut self, raw: Inst, span: &dyn Spanned) { + pub(crate) fn push(&mut self, raw: Inst, span: &dyn Spanned) -> compile::Result<()> { if let Inst::Call { hash, .. } = raw { self.required_functions .entry(hash) - .or_default() - .push((span.span(), self.location.source_id)); + .or_try_default()? + .try_push((span.span(), self.location.source_id))?; } - self.inner_push(AssemblyInst::Raw { raw }, span); + self.inner_push(AssemblyInst::Raw { raw }, span)?; + Ok(()) } /// Push a raw instruction. @@ -172,25 +212,21 @@ impl Assembly { span: &dyn Spanned, comment: &dyn fmt::Display, ) -> compile::Result<()> { - use core::fmt::Write; - let pos = self.instructions.len(); - let c = self.comments.entry(pos).or_default(); + let c = self.comments.entry(pos).or_try_default()?; if !c.is_empty() { - c.push_str("; "); - } - - if let Err(fmt::Error) = write!(c, "{}", comment) { - return Err(compile::Error::msg(span, "Failed to write comment")); + c.try_push_str("; ")?; } - self.push(raw, span); + write!(c, "{}", comment)?; + self.push(raw, span)?; Ok(()) } - fn inner_push(&mut self, inst: AssemblyInst, span: &dyn Spanned) { - self.instructions.push((inst, span.span())); + fn inner_push(&mut self, inst: AssemblyInst, span: &dyn Spanned) -> compile::Result<()> { + self.instructions.try_push((inst, span.span()))?; + Ok(()) } } diff --git a/crates/rune/src/compile/compile.rs b/crates/rune/src/compile/compile.rs index 4c9cc2a1c..e799d597c 100644 --- a/crates/rune/src/compile/compile.rs +++ b/crates/rune/src/compile/compile.rs @@ -1,5 +1,5 @@ -use crate::no_std::prelude::*; - +use crate::alloc::prelude::*; +use crate::alloc::{self, try_vec, Box, Vec}; use crate::ast; use crate::ast::{Span, Spanned}; use crate::compile::v1; @@ -29,7 +29,7 @@ pub(crate) fn compile( source_loader: &mut dyn SourceLoader, options: &Options, unit_storage: &mut dyn UnitEncoder, -) -> Result<(), ()> { +) -> alloc::Result<()> { // Shared id generator. let gen = Gen::new(); let const_arena = hir::Arena::new(); @@ -69,22 +69,29 @@ pub(crate) fn compile( Ok(result) => result, Err(error) => { worker.q.diagnostics.error(source_id, error); - return Err(()); + continue; } }; - worker.queue.push_back(Task::LoadFile { + let result = worker.queue.try_push_back(Task::LoadFile { kind: LoadFileKind::Root, source_id, mod_item, mod_item_id: root_item_id, }); + + if let Err(error) = result { + worker + .q + .diagnostics + .error(source_id, compile::Error::from(error)); + } } worker.index(); if worker.q.diagnostics.has_error() { - return Err(()); + return Ok(()); } loop { @@ -102,17 +109,15 @@ pub(crate) fn compile( } } - match worker.q.queue_unused_entries() { - Ok(true) => (), - Ok(false) => break, - Err((source_id, error)) => { - worker.q.diagnostics.error(source_id, error); - } + let mut errors = Vec::new(); + + if worker.q.queue_unused_entries(&mut errors)? { + break; } - } - if worker.q.diagnostics.has_error() { - return Err(()); + for (source_id, error) in errors { + worker.q.diagnostics.error(source_id, error); + } } Ok(()) @@ -129,16 +134,16 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { location: Location, span: &dyn Spanned, asm: &'a mut Assembly, - ) -> v1::Ctxt<'a, 'hir, 'arena> { - v1::Ctxt { + ) -> alloc::Result> { + Ok(v1::Ctxt { source_id: location.source_id, q: self.q.borrow(), asm, - scopes: self::v1::Scopes::new(location.source_id), - contexts: vec![span.span()], + scopes: self::v1::Scopes::new(location.source_id)?, + contexts: try_vec![span.span()], loops: self::v1::Loops::new(), options: self.options, - } + }) } #[tracing::instrument(skip_all)] @@ -171,7 +176,7 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { return Err(compile::Error::new( item_meta.location.span, ErrorKind::MissingItem { - item: self.q.pool.item(item_meta.item).to_owned(), + item: self.q.pool.item(item_meta.item).try_to_owned()?, }, )); } @@ -203,7 +208,7 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { let Some(type_hash) = meta.type_hash_of() else { return Err(compile::Error::expected_meta( &f.ast, - meta.info(self.q.pool), + meta.info(self.q.pool)?, "type for associated function", )); }; @@ -231,7 +236,7 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { &arena, self.q.borrow(), item_meta.location.source_id, - ); + )?; let hir = match &f.ast { FunctionAst::Item(ast) => hir::lowering::item_fn(&mut cx, ast)?, @@ -240,7 +245,7 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { let count = hir.args.len(); - let mut c = self.compiler1(location, span, &mut asm); + let mut c = self.compiler1(location, span, &mut asm)?; assemble::fn_from_item_fn(&mut c, &hir, f.is_instance)?; if !self.q.is_used(&item_meta) { @@ -284,9 +289,9 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { &arena, self.q.borrow(), item_meta.location.source_id, - ); + )?; let hir = hir::lowering::expr_closure_secondary(&mut cx, &closure.ast, captures)?; - let mut c = self.compiler1(location, &closure.ast, &mut asm); + let mut c = self.compiler1(location, &closure.ast, &mut asm)?; assemble::expr_closure_secondary(&mut c, &hir, &closure.ast)?; if !c.q.is_used(&item_meta) { @@ -317,9 +322,9 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { &arena, self.q.borrow(), item_meta.location.source_id, - ); + )?; let hir = hir::lowering::async_block_secondary(&mut cx, &b.ast, captures)?; - let mut c = self.compiler1(location, &b.ast, &mut asm); + let mut c = self.compiler1(location, &b.ast, &mut asm)?; assemble::async_block_secondary(&mut c, &hir)?; if !self.q.is_used(&item_meta) { @@ -374,7 +379,7 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { Some(item_id) => { let item = self.q.pool.item(item_id); - if self.q.context.contains_prefix(item) || self.q.contains_prefix(item) { + if self.q.context.contains_prefix(item)? || self.q.contains_prefix(item)? { None } else { Some(item_id) @@ -387,7 +392,7 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { return Err(compile::Error::new( location, ErrorKind::MissingItem { - item: self.q.pool.item(item).to_owned(), + item: self.q.pool.item(item).try_to_owned()?, }, )); } @@ -408,7 +413,7 @@ impl<'arena> CompileBuildEntry<'_, 'arena> { return Err(compile::Error::new( location.span, ErrorKind::MissingItem { - item: self.q.pool.item(item_meta.item).to_owned(), + item: self.q.pool.item(item_meta.item).try_to_owned()?, }, )); }; @@ -438,19 +443,19 @@ where for arg in arguments { match arg { ast::FnArg::SelfValue(..) => { - args.push("self".into()); + args.try_push(Box::try_from("self")?)?; } ast::FnArg::Pat(pat) => { let span = pat.span(); if let Some(s) = sources.source(location.source_id, span) { - args.push(s.into()); + args.try_push(Box::try_from(s)?)?; } else { - args.push("*".into()); + args.try_push(Box::try_from("*")?)?; } } } } - Ok(args.into()) + Ok(args.try_into_boxed_slice()?) } diff --git a/crates/rune/src/compile/compile_visitor.rs b/crates/rune/src/compile/compile_visitor.rs index 7b69af5f8..4aef518e1 100644 --- a/crates/rune/src/compile/compile_visitor.rs +++ b/crates/rune/src/compile/compile_visitor.rs @@ -11,7 +11,9 @@ pub trait CompileVisitor { } /// Mark that we've resolved a specific compile meta at the given location. - fn visit_meta(&mut self, _location: &dyn Located, _meta: MetaRef<'_>) {} + fn visit_meta(&mut self, _location: &dyn Located, _meta: MetaRef<'_>) -> Result<(), MetaError> { + Ok(()) + } /// Visit a variable use. fn visit_variable_use( @@ -19,11 +21,14 @@ pub trait CompileVisitor { _source_id: SourceId, _var_span: &dyn Spanned, _span: &dyn Spanned, - ) { + ) -> Result<(), MetaError> { + Ok(()) } /// Visit something that is a module. - fn visit_mod(&mut self, _location: &dyn Located) {} + fn visit_mod(&mut self, _location: &dyn Located) -> Result<(), MetaError> { + Ok(()) + } /// Visit anterior `///`-style comments, and interior `//!`-style doc /// comments for an item. @@ -39,7 +44,8 @@ pub trait CompileVisitor { _item: &Item, _hash: Hash, _docstr: &str, - ) { + ) -> Result<(), MetaError> { + Ok(()) } /// Visit anterior `///`-style comments, and interior `//!`-style doc @@ -54,13 +60,16 @@ pub trait CompileVisitor { _hash: Hash, _field: &str, _docstr: &str, - ) { + ) -> Result<(), MetaError> { + Ok(()) } } /// A [CompileVisitor] which does nothing. +#[cfg(feature = "std")] pub(crate) struct NoopCompileVisitor(()); +#[cfg(feature = "std")] impl NoopCompileVisitor { /// Construct a new noop compile visitor. pub(crate) const fn new() -> Self { @@ -68,4 +77,5 @@ impl NoopCompileVisitor { } } +#[cfg(feature = "std")] impl CompileVisitor for NoopCompileVisitor {} diff --git a/crates/rune/src/compile/context.rs b/crates/rune/src/compile/context.rs index 702fd1ed5..f3944871e 100644 --- a/crates/rune/src/compile/context.rs +++ b/crates/rune/src/compile/context.rs @@ -1,9 +1,10 @@ use core::fmt; -use crate::no_std::collections::{BTreeSet, HashMap, HashSet}; -use crate::no_std::prelude::*; use crate::no_std::sync::Arc; +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, BTreeSet, Box, HashMap, HashSet, Vec}; use crate::compile::meta; #[cfg(feature = "doc")] use crate::compile::Docs; @@ -38,13 +39,13 @@ pub(crate) struct ContextMeta { impl ContextMeta { #[cfg(feature = "emit")] - pub(crate) fn info(&self) -> MetaInfo { + pub(crate) fn info(&self) -> alloc::Result { MetaInfo::new(&self.kind, self.hash, self.item.as_deref()) } } /// Information on a specific type. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] #[non_exhaustive] pub(crate) struct ContextType { /// Item of the type. @@ -180,14 +181,17 @@ impl Context { /// /// let context = Context::with_default_modules()?; /// - /// let runtime = Arc::new(context.runtime()); + /// let runtime = Arc::new(context.runtime()?); /// let unit = Arc::new(Unit::default()); /// /// let vm = Vm::new(runtime, unit); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn runtime(&self) -> RuntimeContext { - RuntimeContext::new(self.functions.clone(), self.constants.clone()) + pub fn runtime(&self) -> alloc::Result { + Ok(RuntimeContext::new( + self.functions.try_clone()?, + self.constants.try_clone()?, + )) } /// Install the specified module. @@ -202,13 +206,13 @@ impl Context { let module = module.as_ref(); if let Some(id) = module.unique { - if !self.unique.insert(id) { + if !self.unique.try_insert(id)? { return Ok(()); } } if let Some(ComponentRef::Crate(name)) = module.item.first() { - self.crates.insert(name.into()); + self.crates.try_insert(name.try_into()?)?; } self.install_module(module)?; @@ -270,7 +274,7 @@ impl Context { pub(crate) fn iter_components<'a, I: 'a>( &'a self, iter: I, - ) -> impl Iterator> + 'a + ) -> alloc::Result> + 'a> where I: IntoIterator, I::Item: IntoComponent, @@ -314,7 +318,7 @@ impl Context { } /// Check if unit contains the given name by prefix. - pub(crate) fn contains_prefix(&self, item: &Item) -> bool { + pub(crate) fn contains_prefix(&self, item: &Item) -> alloc::Result { self.names.contains_prefix(item) } @@ -375,21 +379,24 @@ impl Context { self.names.insert(item)?; self.item_to_hash - .entry(item.clone()) - .or_default() - .insert(meta.hash); + .entry(item.try_clone()?) + .or_try_default()? + .try_insert(meta.hash)?; } #[cfg(feature = "doc")] if let Some(h) = meta.kind.associated_container() { - let assoc = self.associated.entry(h).or_default(); - assoc.push(meta.hash); + let assoc = self.associated.entry(h).or_try_default()?; + assoc.try_push(meta.hash)?; } let hash = meta.hash; let index = self.meta.len(); - self.meta.push(meta); - self.hash_to_meta.entry(hash).or_default().push(index); + self.meta.try_push(meta)?; + self.hash_to_meta + .entry(hash) + .or_try_default()? + .try_push(index)?; Ok(()) } @@ -403,10 +410,10 @@ impl Context { while let Some((item, docs)) = current.take() { self.install_meta(ContextMeta { hash: Hash::type_hash(item), - item: Some(item.to_owned()), + item: Some(item.try_to_owned()?), kind: meta::Kind::Module, #[cfg(feature = "doc")] - docs: docs.cloned().unwrap_or_default(), + docs: docs.try_cloned()?.unwrap_or_default(), })?; current = item.parent().map(|item| (item, None)); @@ -417,13 +424,13 @@ impl Context { /// Install a single type. fn install_type(&mut self, module: &Module, ty: &ModuleType) -> Result<(), ContextError> { - let item = module.item.join(&ty.item); + let item = module.item.join(&ty.item)?; self.install_type_info(ContextType { - item: item.clone(), + item: item.try_clone()?, hash: ty.hash, type_check: None, - type_info: ty.type_info.clone(), + type_info: ty.type_info.try_clone()?, type_parameters: ty.type_parameters, })?; @@ -450,7 +457,7 @@ impl Context { #[cfg(feature = "doc")] return_type: Some(ty.hash), #[cfg(feature = "doc")] - argument_types: Box::from([]), + argument_types: Box::default(), }; self.insert_native_fn(hash, c)?; @@ -467,9 +474,12 @@ impl Context { .copied() .enumerate() .map(|(position, name)| { - (Box::::from(name), meta::FieldMeta { position }) + Ok(( + Box::::try_from(name)?, + meta::FieldMeta { position }, + )) }) - .collect(), + .try_collect::>()??, }), Fields::Unnamed(args) => meta::Fields::Unnamed(*args), Fields::Empty => meta::Fields::Empty, @@ -484,17 +494,17 @@ impl Context { continue; }; - let item = item.extended(variant.name); + let item = item.extended(variant.name)?; let hash = Hash::type_hash(&item); self.install_type_info(ContextType { - item: item.clone(), + item: item.try_clone()?, hash, type_check: None, type_info: TypeInfo::Variant(Arc::new(VariantRtti { enum_hash: ty.hash, hash, - item: item.clone(), + item: item.try_clone()?, })), type_parameters: Hash::EMPTY, })?; @@ -514,7 +524,7 @@ impl Context { #[cfg(feature = "doc")] return_type: Some(ty.hash), #[cfg(feature = "doc")] - argument_types: Box::from([]), + argument_types: Box::default(), }; self.insert_native_fn(hash, c)?; @@ -537,12 +547,12 @@ impl Context { .copied() .enumerate() .map(|(position, name)| { - ( - Box::::from(name), + Ok(( + Box::::try_from(name)?, meta::FieldMeta { position }, - ) + )) }) - .collect(), + .try_collect::>()??, }) } Fields::Unnamed(args) => meta::Fields::Unnamed(*args), @@ -551,7 +561,7 @@ impl Context { constructor, }, #[cfg(feature = "doc")] - docs: variant.docs.clone(), + docs: variant.docs.try_clone()?, })?; } @@ -567,7 +577,7 @@ impl Context { item: Some(item), kind, #[cfg(feature = "doc")] - docs: ty.docs.clone(), + docs: ty.docs.try_clone()?, })?; Ok(()) @@ -585,12 +595,12 @@ impl Context { }); } - self.constants.insert( + self.constants.try_insert( Hash::associated_function(ty.hash, Protocol::INTO_TYPE_NAME), - ConstValue::String(ty.item.to_string()), - ); + ConstValue::String(ty.item.try_to_string()?), + )?; - if let Some(old) = self.types.insert(ty.hash, ty) { + if let Some(old) = self.types.try_insert(ty.hash, ty)? { return Err(ContextError::ConflictingType { item: old.item, type_info: old.type_info, @@ -607,21 +617,21 @@ impl Context { module: &Module, f: &ModuleFunction, ) -> Result<(), ContextError> { - let item = module.item.join(&f.item); + let item = module.item.join(&f.item)?; self.names.insert(&item)?; let hash = Hash::type_hash(&item); - self.constants.insert( + self.constants.try_insert( Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), - ConstValue::String(item.to_string()), - ); + ConstValue::String(item.try_to_string()?), + )?; let signature = meta::Signature { #[cfg(feature = "doc")] is_async: f.is_async, #[cfg(feature = "doc")] - deprecated: f.deprecated.clone(), + deprecated: f.deprecated.try_clone()?, #[cfg(feature = "doc")] args: f.args, #[cfg(feature = "doc")] @@ -631,7 +641,7 @@ impl Context { .argument_types .iter() .map(|f| f.as_ref().map(|f| f.hash)) - .collect(), + .try_collect()?, }; self.insert_native_fn(hash, &f.handler)?; @@ -651,7 +661,7 @@ impl Context { parameter_types: Vec::new(), }, #[cfg(feature = "doc")] - docs: f.docs.clone(), + docs: f.docs.try_clone()?, })?; Ok(()) @@ -659,16 +669,16 @@ impl Context { /// Install a macro and check for duplicates. fn install_macro(&mut self, module: &Module, m: &ModuleMacro) -> Result<(), ContextError> { - let item = module.item.join(&m.item); + let item = module.item.join(&m.item)?; let hash = Hash::type_hash(&item); - self.macros.insert(hash, m.handler.clone()); + self.macros.try_insert(hash, m.handler.clone())?; self.install_meta(ContextMeta { hash, item: Some(item), kind: meta::Kind::Macro, #[cfg(feature = "doc")] - docs: m.docs.clone(), + docs: m.docs.try_clone()?, })?; Ok(()) @@ -680,16 +690,16 @@ impl Context { module: &Module, m: &ModuleAttributeMacro, ) -> Result<(), ContextError> { - let item = module.item.join(&m.item); + let item = module.item.join(&m.item)?; let hash = Hash::type_hash(&item); - self.attribute_macros.insert(hash, m.handler.clone()); + self.attribute_macros.try_insert(hash, m.handler.clone())?; self.install_meta(ContextMeta { hash, item: Some(item), kind: meta::Kind::AttributeMacro, #[cfg(feature = "doc")] - docs: m.docs.clone(), + docs: m.docs.try_clone()?, })?; Ok(()) @@ -701,25 +711,25 @@ impl Context { module: &Module, m: &ModuleConstant, ) -> Result<(), ContextError> { - let item = module.item.join(&m.item); + let item = module.item.join(&m.item)?; let hash = Hash::type_hash(&item); - self.constants.insert(hash, m.value.clone()); + self.constants.try_insert(hash, m.value.try_clone()?)?; self.install_meta(ContextMeta { hash, item: Some(item), kind: meta::Kind::Const, #[cfg(feature = "doc")] - docs: m.docs.clone(), + docs: m.docs.try_clone()?, })?; Ok(()) } fn install_associated(&mut self, assoc: &ModuleAssociated) -> Result<(), ContextError> { - let Some(info) = self.types.get(&assoc.container.hash).cloned() else { + let Some(info) = self.types.get(&assoc.container.hash).try_cloned()? else { return Err(ContextError::MissingContainer { - container: assoc.container_type_info.clone(), + container: assoc.container_type_info.try_clone()?, }); }; @@ -735,7 +745,7 @@ impl Context { #[cfg(feature = "doc")] is_async: assoc.is_async, #[cfg(feature = "doc")] - deprecated: assoc.deprecated.clone(), + deprecated: assoc.deprecated.try_clone()?, #[cfg(feature = "doc")] args: assoc.args, #[cfg(feature = "doc")] @@ -745,11 +755,9 @@ impl Context { .argument_types .iter() .map(|f| f.as_ref().map(|f| f.hash)) - .collect(), + .try_collect()?, }; - self.insert_native_fn(hash, &assoc.handler)?; - // If the associated function is a named instance function - register it // under the name of the item it corresponds to unless it's a field // function. @@ -757,16 +765,16 @@ impl Context { // The other alternatives are protocol functions (which are not free) // and plain hashes. let item = if let meta::AssociatedKind::Instance(name) = &assoc.name.associated { - let item = info.item.extended(name.as_ref()); + let item = info.item.extended(name.as_ref())?; let hash = Hash::type_hash(&item) .with_type_parameters(info.type_parameters) .with_function_parameters(assoc.name.function_parameters); - self.constants.insert( + self.constants.try_insert( Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), - ConstValue::String(item.to_string()), - ); + ConstValue::String(item.try_to_string()?), + )?; self.insert_native_fn(hash, &assoc.handler)?; Some(item) @@ -774,11 +782,13 @@ impl Context { None }; + self.insert_native_fn(hash, &assoc.handler)?; + self.install_meta(ContextMeta { hash, item, kind: meta::Kind::Function { - associated: Some(assoc.name.associated.clone()), + associated: Some(assoc.name.associated.try_clone()?), signature, is_test: false, is_bench: false, @@ -788,10 +798,10 @@ impl Context { #[cfg(feature = "doc")] container: Some(assoc.container.hash), #[cfg(feature = "doc")] - parameter_types: assoc.name.parameter_types.clone(), + parameter_types: assoc.name.parameter_types.try_clone()?, }, #[cfg(feature = "doc")] - docs: assoc.docs.clone(), + docs: assoc.docs.try_clone()?, })?; Ok(()) @@ -803,28 +813,28 @@ impl Context { module: &Module, internal_enum: &InternalEnum, ) -> Result<(), ContextError> { - if !self.internal_enums.insert(internal_enum.static_type) { + if !self.internal_enums.try_insert(internal_enum.static_type)? { return Err(ContextError::InternalAlreadyPresent { name: internal_enum.name, }); } - let item = module.item.join(&internal_enum.base_type); + let item = module.item.join(&internal_enum.base_type)?; let enum_hash = internal_enum.static_type.hash; self.install_meta(ContextMeta { hash: enum_hash, - item: Some(item.clone()), + item: Some(item.try_clone()?), kind: meta::Kind::Enum { parameters: Hash::EMPTY, }, #[cfg(feature = "doc")] - docs: internal_enum.docs.clone(), + docs: internal_enum.docs.try_clone()?, })?; self.install_type_info(ContextType { - item: item.clone(), + item: item.try_clone()?, hash: enum_hash, type_check: None, type_info: internal_enum.static_type.type_info(), @@ -836,11 +846,11 @@ impl Context { continue; }; - let item = item.extended(variant.name); + let item = item.extended(variant.name)?; let hash = Hash::type_hash(&item); self.install_type_info(ContextType { - item: item.clone(), + item: item.try_clone()?, hash, type_check: variant.type_check, type_info: internal_enum.static_type.type_info(), @@ -864,7 +874,7 @@ impl Context { #[cfg(feature = "doc")] return_type: Some(enum_hash), #[cfg(feature = "doc")] - argument_types: Box::from([]), + argument_types: Box::default(), }) } else { None @@ -883,9 +893,9 @@ impl Context { .copied() .enumerate() .map(|(position, name)| { - (Box::::from(name), meta::FieldMeta { position }) + Ok((Box::::try_from(name)?, meta::FieldMeta { position })) }) - .collect(), + .try_collect::>()??, }), Fields::Unnamed(args) => meta::Fields::Unnamed(*args), Fields::Empty => meta::Fields::Empty, @@ -893,7 +903,7 @@ impl Context { constructor, }, #[cfg(feature = "doc")] - docs: variant.docs.clone(), + docs: variant.docs.try_clone()?, })?; } @@ -909,7 +919,7 @@ impl Context { return Err(ContextError::ConflictingFunction { hash }); } - self.functions.insert(hash, handler.clone()); + self.functions.try_insert(hash, handler.clone())?; Ok(()) } diff --git a/crates/rune/src/compile/context_error.rs b/crates/rune/src/compile/context_error.rs index a3d781ae5..18547153d 100644 --- a/crates/rune/src/compile/context_error.rs +++ b/crates/rune/src/compile/context_error.rs @@ -1,8 +1,6 @@ use core::fmt; -use crate::no_std::prelude::*; - -use crate::alloc::AllocError; +use crate::alloc::{self, Box}; use crate::compile::ItemBuf; use crate::runtime::{TypeInfo, VmError}; use crate::Hash; @@ -13,7 +11,7 @@ use crate::Hash; #[non_exhaustive] pub enum ContextError { AllocError { - error: AllocError, + error: alloc::Error, }, UnitAlreadyPresent, InternalAlreadyPresent { @@ -115,12 +113,22 @@ pub enum ContextError { }, } -impl From for ContextError { - fn from(error: AllocError) -> Self { +impl From for ContextError { + #[inline] + fn from(error: alloc::Error) -> Self { ContextError::AllocError { error } } } +impl From for ContextError { + #[inline] + fn from(error: alloc::alloc::AllocError) -> Self { + ContextError::AllocError { + error: error.into(), + } + } +} + impl fmt::Display for ContextError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { diff --git a/crates/rune/src/compile/docs.rs b/crates/rune/src/compile/docs.rs index 8745e91c9..cb94fcc17 100644 --- a/crates/rune/src/compile/docs.rs +++ b/crates/rune/src/compile/docs.rs @@ -1,10 +1,13 @@ +use crate as rune; +use crate::alloc; +use crate::alloc::prelude::*; #[cfg(feature = "doc")] -use crate::no_std::prelude::*; +use crate::alloc::{String, Vec}; /// The documentation for a function. /// /// If the `doc` feature is disabled, this is a zero-sized type. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct Docs { /// Lines of documentation. #[cfg(feature = "doc")] @@ -36,7 +39,7 @@ impl Docs { /// Update documentation. #[cfg(feature = "doc")] - pub(crate) fn set_docs(&mut self, docs: S) + pub(crate) fn set_docs(&mut self, docs: S) -> alloc::Result<()> where S: IntoIterator, S::Item: AsRef, @@ -44,21 +47,24 @@ impl Docs { self.docs.clear(); for line in docs { - self.docs.push(line.as_ref().to_owned()); + self.docs.try_push(line.as_ref().try_to_owned()?)?; } + + Ok(()) } #[cfg(not(feature = "doc"))] - pub(crate) fn set_docs(&mut self, _: S) + pub(crate) fn set_docs(&mut self, _: S) -> alloc::Result<()> where S: IntoIterator, S::Item: AsRef, { + Ok(()) } /// Update arguments. #[cfg(feature = "doc")] - pub(crate) fn set_arguments(&mut self, arguments: S) + pub(crate) fn set_arguments(&mut self, arguments: S) -> alloc::Result<()> where S: IntoIterator, S::Item: AsRef, @@ -67,18 +73,20 @@ impl Docs { out.clear(); for argument in arguments { - out.push(argument.as_ref().to_owned()); + out.try_push(argument.as_ref().try_to_owned()?)?; } self.arguments = Some(out); + Ok(()) } #[cfg(not(feature = "doc"))] - pub(crate) fn set_arguments(&mut self, _: S) + pub(crate) fn set_arguments(&mut self, _: S) -> alloc::Result<()> where S: IntoIterator, S::Item: AsRef, { + Ok(()) } } diff --git a/crates/rune/src/compile/error.rs b/crates/rune/src/compile/error.rs index 0035e82b7..ec14297f3 100644 --- a/crates/rune/src/compile/error.rs +++ b/crates/rune/src/compile/error.rs @@ -1,10 +1,11 @@ use core::fmt; use crate::no_std::io; -use crate::no_std::path::PathBuf; -use crate::no_std::prelude::*; -use crate::alloc::AllocError; +use crate as rune; +use crate::alloc::path::PathBuf; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, String, Vec}; use crate::ast; use crate::ast::unescape; use crate::ast::{Span, Spanned}; @@ -23,7 +24,9 @@ use crate::{Hash, SourceId}; #[derive(Debug)] pub struct Error { span: Span, - kind: Box, + // Errors are exempt from fallible allocations since they're not commonly + // constructed. + kind: rust_alloc::boxed::Box, } impl Error { @@ -35,7 +38,7 @@ impl Error { { Self { span: span.span(), - kind: Box::new(ErrorKind::from(kind)), + kind: rust_alloc::boxed::Box::new(ErrorKind::from(kind)), } } @@ -43,13 +46,11 @@ impl Error { pub fn msg(span: S, message: M) -> Self where S: Spanned, - M: fmt::Display, + M: fmt::Display + fmt::Debug + Send + Sync + 'static, { Self { span: span.span(), - kind: Box::new(ErrorKind::Custom { - message: message.to_string().into(), - }), + kind: rust_alloc::boxed::Box::new(ErrorKind::msg(message)), } } @@ -85,33 +86,34 @@ impl fmt::Display for Error { } } -impl From> for Error +impl From> for Error where + S: Spanned, ErrorKind: From, { - fn from(spanned: HasSpan) -> Self { - Error { - span: spanned.span, - kind: Box::new(ErrorKind::from(spanned.error)), - } + fn from(spanned: HasSpan) -> Self { + Self::new(spanned.span(), spanned.into_inner()) } } impl From for ErrorKind { #[inline] fn from(error: ir::scopes::MissingLocal) -> Self { - ErrorKind::MissingLocal { - name: error.0.to_string(), - } + ErrorKind::MissingLocal { name: error.0 } + } +} + +impl From for ErrorKind { + #[inline] + fn from(error: anyhow::Error) -> Self { + ErrorKind::Custom { error } } } impl From<&'static str> for ErrorKind { #[inline] fn from(value: &'static str) -> Self { - ErrorKind::Custom { - message: Box::from(value), - } + ErrorKind::msg(value) } } @@ -122,10 +124,28 @@ where { #[inline] fn from(kind: Box) -> Self { + ErrorKind::from(Box::into_inner(kind)) + } +} + +// TODO: remove implementation. +impl From> for ErrorKind +where + ErrorKind: From, +{ + #[inline] + fn from(kind: rust_alloc::boxed::Box) -> Self { ErrorKind::from(*kind) } } +impl From for rust_alloc::boxed::Box { + #[inline] + fn from(error: alloc::Error) -> Self { + rust_alloc::boxed::Box::new(ErrorKind::from(error)) + } +} + impl Error { /// Error when we got mismatched meta. pub fn expected_meta(spanned: S, meta: MetaInfo, expected: &'static str) -> Self @@ -185,7 +205,7 @@ impl Error { #[non_exhaustive] pub(crate) enum ErrorKind { Custom { - message: Box, + error: anyhow::Error, }, Expected { actual: Expectation, @@ -195,7 +215,7 @@ pub(crate) enum ErrorKind { what: Expectation, }, AllocError { - error: rune_alloc::Error, + error: alloc::Error, }, IrError(IrErrorKind), MetaError(MetaError), @@ -224,7 +244,7 @@ pub(crate) enum ErrorKind { }, MissingSelf, MissingLocal { - name: String, + name: Box, }, MissingItem { item: ItemBuf, @@ -480,6 +500,17 @@ pub(crate) enum ErrorKind { UnsupportedSuffix, } +impl ErrorKind { + pub(crate) fn msg(message: M) -> Self + where + M: fmt::Display + fmt::Debug + Send + Sync + 'static, + { + Self::Custom { + error: anyhow::Error::msg(message), + } + } +} + impl crate::no_std::error::Error for ErrorKind { fn source(&self) -> Option<&(dyn crate::no_std::error::Error + 'static)> { match self { @@ -503,19 +534,14 @@ impl crate::no_std::error::Error for ErrorKind { impl fmt::Display for ErrorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - ErrorKind::Custom { message } => { - write!(f, "{message}", message = message)?; + ErrorKind::Custom { error } => { + error.fmt(f)?; } ErrorKind::Expected { actual, expected } => { - write!( - f, - "Expected `{expected}`, but got `{actual}`", - expected = expected, - actual = actual - )?; + write!(f, "Expected `{expected}`, but got `{actual}`",)?; } ErrorKind::Unsupported { what } => { - write!(f, "Unsupported `{what}`", what = what)?; + write!(f, "Unsupported `{what}`")?; } ErrorKind::AllocError { error } => { error.fmt(f)?; @@ -551,12 +577,7 @@ impl fmt::Display for ErrorKind { error.fmt(f)?; } ErrorKind::FileError { path, error } => { - write!( - f, - "Failed to load `{path}`: {error}", - path = path.display(), - error = error - )?; + write!(f, "Failed to load `{path}`: {error}", path = path.display(),)?; } ErrorKind::ModNotFound { path } => { write!( @@ -616,7 +637,7 @@ impl fmt::Display for ErrorKind { write!(f, "Unsupported binary operator `{op}`")?; } ErrorKind::UnsupportedLitObject { meta } => { - write!(f, "Item `{meta}` is not an object", meta = meta)?; + write!(f, "Item `{meta}` is not an object")?; } ErrorKind::LitObjectMissingField { field, item } => { write!(f, "Missing field `{field}` in declaration of `{item}`",)?; @@ -730,7 +751,7 @@ impl fmt::Display for ErrorKind { write!(f, "Conflicting function hash already exists `{hash}`",)?; } ErrorKind::ConstantConflict { hash } => { - write!(f, "Conflicting constant for hash `{hash}`", hash = hash)?; + write!(f, "Conflicting constant for hash `{hash}`")?; } ErrorKind::StaticStringMissing { hash, slot } => { write!( @@ -892,7 +913,7 @@ impl fmt::Display for ErrorKind { write!(f, "Can only specify one attribute named `{name}`",)?; } ErrorKind::MissingSourceId { source_id } => { - write!(f, "Missing source id `{source_id}`", source_id = source_id)?; + write!(f, "Missing source id `{source_id}`")?; } ErrorKind::ExpectedMultilineCommentTerm => { write!(f, "Expected multiline comment to be terminated with a `*/`")?; @@ -970,11 +991,7 @@ impl fmt::Display for ErrorKind { )?; } ErrorKind::ArenaAllocError { requested } => { - write!( - f, - "Allocation error for {requested} bytes", - requested = requested - )?; + write!(f, "Allocation error for {requested} bytes",)?; } ErrorKind::UnsupportedPatternRest => { write!(f, "Pattern `..` is not supported in this location")?; @@ -997,22 +1014,34 @@ impl fmt::Display for ErrorKind { } } -impl From for ErrorKind { +impl From for Error { #[inline] - fn from(error: AllocError) -> Self { - ErrorKind::AllocError { - error: error.into(), - } + fn from(error: alloc::Error) -> Self { + Error::new(Span::empty(), ErrorKind::AllocError { error }) } } -impl From for ErrorKind { +impl From for ErrorKind { #[inline] - fn from(error: rune_alloc::Error) -> Self { + fn from(error: alloc::Error) -> Self { ErrorKind::AllocError { error } } } +impl From for Error { + #[inline] + fn from(error: alloc::alloc::AllocError) -> Self { + Self::from(alloc::Error::from(error)) + } +} + +impl From for ErrorKind { + #[inline] + fn from(error: alloc::alloc::AllocError) -> Self { + Self::from(alloc::Error::from(error)) + } +} + impl From for ErrorKind { #[inline] fn from(error: IrErrorKind) -> Self { @@ -1176,7 +1205,7 @@ impl fmt::Display for IrErrorKind { /// A single step in an import. /// /// This is used to indicate a step in an import chain in an error message. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] #[non_exhaustive] pub struct ImportStep { /// The location of the import. @@ -1188,7 +1217,7 @@ pub struct ImportStep { /// A meta error. #[derive(Debug)] pub struct MetaError { - kind: Box, + kind: ::rust_alloc::boxed::Box, } impl MetaError { @@ -1198,23 +1227,30 @@ impl MetaError { MetaErrorKind: From, { Self { - kind: Box::new(kind.into()), + kind: ::rust_alloc::boxed::Box::new(kind.into()), } } } -impl From for MetaError { +impl From for MetaError { #[inline] - fn from(error: AllocError) -> Self { + fn from(error: alloc::Error) -> Self { Self::new(MetaErrorKind::AllocError { error }) } } +impl From for MetaError { + #[inline] + fn from(error: alloc::alloc::AllocError) -> Self { + Self::from(alloc::Error::from(error)) + } +} + #[derive(Debug)] /// Tried to add an item that already exists. pub(crate) enum MetaErrorKind { AllocError { - error: AllocError, + error: alloc::Error, }, MetaConflict { /// The meta we tried to insert. diff --git a/crates/rune/src/compile/ir.rs b/crates/rune/src/compile/ir.rs index ab4448eb0..37a5fcee0 100644 --- a/crates/rune/src/compile/ir.rs +++ b/crates/rune/src/compile/ir.rs @@ -11,9 +11,9 @@ mod value; use core::ops::{AddAssign, MulAssign, ShlAssign, ShrAssign, SubAssign}; -use crate::no_std::prelude::*; - use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{Box, Vec}; use crate::ast::{self, Span, Spanned}; use crate::compile::ir; use crate::compile::{self, WithSpan}; @@ -31,7 +31,7 @@ pub(crate) use self::value::Value; impl ast::Expr { pub(crate) fn eval(&self, cx: &mut MacroContext<'_, '_, '_>) -> compile::Result { - let mut expr = self.clone(); + let mut expr = self.try_clone()?; index::expr(cx.idx, &mut expr)?; let ir = { @@ -41,7 +41,7 @@ impl ast::Expr { &arena, cx.idx.q.borrow(), cx.item_meta.location.source_id, - ); + )?; let hir = hir::lowering::expr(&mut hir_ctx, &expr)?; let mut cx = Ctxt { @@ -54,7 +54,7 @@ impl ast::Expr { let mut ir_interpreter = Interpreter { budget: Budget::new(1_000_000), - scopes: Default::default(), + scopes: Scopes::new()?, module: cx.item_meta.module, item: cx.item_meta.item, q: cx.idx.q.borrow(), @@ -87,7 +87,7 @@ macro_rules! decl_kind { } /// A single operation in the Rune intermediate language. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct Ir { #[rune(span)] pub(crate) span: Span, @@ -109,7 +109,7 @@ impl Ir { } /// The target of a set operation. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrTarget { /// Span of the target. #[rune(span)] @@ -119,7 +119,7 @@ pub(crate) struct IrTarget { } /// The kind of the target. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) enum IrTargetKind { /// A variable. Name(hir::OwnedName), @@ -131,7 +131,7 @@ pub(crate) enum IrTargetKind { decl_kind! { /// The kind of an intermediate operation. - #[derive(Debug, Clone)] + #[derive(Debug, TryClone)] pub(crate) enum IrKind { /// Push a scope with the given instructions. Scope(IrScope), @@ -170,7 +170,7 @@ decl_kind! { } /// An interpeted function. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrFn { /// The span of the function. #[rune(span)] @@ -194,7 +194,7 @@ impl IrFn { .. }) = arg { - args.push(hir::Name::Str(name).into_owned()); + args.try_push(hir::Name::Str(name).into_owned()?)?; continue; } @@ -212,7 +212,7 @@ impl IrFn { } /// Definition of a new variable scope. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrScope { /// The span of the scope. #[rune(span)] @@ -224,7 +224,7 @@ pub(crate) struct IrScope { } /// A binary operation. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrBinary { /// The span of the binary op. #[rune(span)] @@ -238,7 +238,7 @@ pub(crate) struct IrBinary { } /// A local variable declaration. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrDecl { /// The span of the declaration. #[rune(span)] @@ -250,7 +250,7 @@ pub(crate) struct IrDecl { } /// Set a target. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrSet { /// The span of the set operation. #[rune(span)] @@ -262,7 +262,7 @@ pub(crate) struct IrSet { } /// Assign a target. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrAssign { /// The span of the set operation. #[rune(span)] @@ -276,7 +276,7 @@ pub(crate) struct IrAssign { } /// A string template. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrTemplate { /// The span of the template. #[rune(span)] @@ -286,7 +286,7 @@ pub(crate) struct IrTemplate { } /// A string template. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) enum IrTemplateComponent { /// An ir expression. Ir(Ir), @@ -295,7 +295,7 @@ pub(crate) enum IrTemplateComponent { } /// Branch conditions in intermediate representation. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrBranches { /// Span associated with branches. #[rune(span)] @@ -307,7 +307,7 @@ pub(crate) struct IrBranches { } /// The condition for a branch. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) enum IrCondition { /// A simple conditional ir expression. Ir(Ir), @@ -316,7 +316,7 @@ pub(crate) enum IrCondition { } /// A pattern match. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrLet { /// The span of the let condition. #[rune(span)] @@ -328,7 +328,7 @@ pub(crate) struct IrLet { } /// A pattern. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) enum IrPat { /// An ignore pattern `_`. Ignore, @@ -341,7 +341,7 @@ impl IrPat { match hir.kind { hir::PatKind::Ignore => return Ok(ir::IrPat::Ignore), hir::PatKind::Path(&hir::PatPathKind::Ident(name)) => { - return Ok(ir::IrPat::Binding(hir::Name::Str(name).into_owned())); + return Ok(ir::IrPat::Binding(hir::Name::Str(name).into_owned()?)); } _ => (), } @@ -369,7 +369,7 @@ impl IrPat { } /// A loop with an optional condition. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrLoop { /// The span of the loop. #[rune(span)] @@ -383,7 +383,7 @@ pub(crate) struct IrLoop { } /// A break operation. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrBreak { /// The span of the break. #[rune(span)] @@ -400,10 +400,10 @@ impl IrBreak { cx: &mut Ctxt<'_, '_>, hir: &hir::ExprBreak, ) -> compile::Result { - let label = hir.label.map(Into::into); + let label = hir.label.map(TryInto::try_into).transpose()?; let expr = match hir.expr { - Some(e) => Some(Box::new(compiler::expr(e, cx)?)), + Some(e) => Some(Box::try_new(compiler::expr(e, cx)?)?), None => None, }; @@ -426,12 +426,17 @@ impl IrBreak { None => None, }; - ir::EvalOutcome::Break(span, self.label.clone(), expr) + let label = match self.label.try_clone() { + Ok(label) => label, + Err(error) => return error.into(), + }; + + ir::EvalOutcome::Break(span, label, expr) } } /// Tuple expression. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct Tuple { /// Span of the tuple. #[rune(span)] @@ -441,7 +446,7 @@ pub(crate) struct Tuple { } /// Object expression. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrObject { /// Span of the object. #[rune(span)] @@ -451,7 +456,7 @@ pub(crate) struct IrObject { } /// Call expressions. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrCall { /// Span of the call. #[rune(span)] @@ -463,7 +468,7 @@ pub(crate) struct IrCall { } /// Vector expression. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) struct IrVec { /// Span of the vector. #[rune(span)] @@ -473,7 +478,8 @@ pub(crate) struct IrVec { } /// A binary operation. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) enum IrBinaryOp { /// Add `+`. Add, @@ -500,7 +506,8 @@ pub(crate) enum IrBinaryOp { } /// An assign operation. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) enum IrAssignOp { /// `+=`. Add, diff --git a/crates/rune/src/compile/ir/compiler.rs b/crates/rune/src/compile/ir/compiler.rs index b172a817a..eced1a697 100644 --- a/crates/rune/src/compile/ir/compiler.rs +++ b/crates/rune/src/compile/ir/compiler.rs @@ -1,7 +1,7 @@ use core::mem::{replace, take}; -use crate::no_std::prelude::*; - +use crate::alloc::prelude::*; +use crate::alloc::{try_format, Box, Vec}; use crate::ast::{self, Span, Spanned}; use crate::compile::ir; use crate::compile::{self, ErrorKind, WithSpan}; @@ -46,14 +46,14 @@ pub(crate) fn expr(hir: &hir::Expr<'_>, c: &mut Ctxt<'_, '_>) -> compile::Result let Some(value) = c.q.get_const_value(hash) else { return Err(compile::Error::msg( hir, - format_args!("Missing constant for hash {hash}"), + try_format!("Missing constant for hash {hash}"), )); }; ir::Ir::new(span, ir::Value::from_const(value).with_span(span)?) } hir::ExprKind::Variable(name) => { - return Ok(ir::Ir::new(span, name.into_owned())); + return Ok(ir::Ir::new(span, name.into_owned()?)); } _ => { return Err(compile::Error::msg( @@ -70,7 +70,7 @@ fn ir_target(expr: &hir::Expr<'_>) -> compile::Result { hir::ExprKind::Variable(name) => { return Ok(ir::IrTarget { span: expr.span(), - kind: ir::IrTargetKind::Name(name.into_owned()), + kind: ir::IrTargetKind::Name(name.into_owned()?), }); } hir::ExprKind::FieldAccess(expr_field_access) => { @@ -80,13 +80,13 @@ fn ir_target(expr: &hir::Expr<'_>) -> compile::Result { hir::ExprField::Ident(name) => { return Ok(ir::IrTarget { span: expr.span(), - kind: ir::IrTargetKind::Field(Box::new(target), name.into()), + kind: ir::IrTargetKind::Field(Box::try_new(target)?, name.try_into()?), }); } hir::ExprField::Index(index) => { return Ok(ir::IrTarget { span: expr.span(), - kind: ir::IrTargetKind::Index(Box::new(target), index), + kind: ir::IrTargetKind::Index(Box::try_new(target)?, index), }); } _ => { @@ -113,7 +113,7 @@ fn expr_assign( ir::IrSet { span, target, - value: Box::new(expr(&hir.rhs, c)?), + value: Box::try_new(expr(&hir.rhs, c)?)?, }, )) } @@ -124,10 +124,10 @@ fn expr_call( c: &mut Ctxt<'_, '_>, hir: &hir::ExprCall<'_>, ) -> compile::Result { - let mut args = Vec::with_capacity(hir.args.len()); + let mut args = Vec::try_with_capacity(hir.args.len())?; for e in hir.args { - args.push(expr(e, c)?); + args.try_push(expr(e, c)?)?; } if let hir::Call::ConstFn { id, .. } = hir.call { @@ -164,7 +164,7 @@ fn expr_binary( ir::IrAssign { span, target, - value: Box::new(expr(&hir.rhs, c)?), + value: Box::try_new(expr(&hir.rhs, c)?)?, op, }, )); @@ -193,8 +193,8 @@ fn expr_binary( ir::IrBinary { span, op, - lhs: Box::new(lhs), - rhs: Box::new(rhs), + lhs: Box::try_new(lhs)?, + rhs: Box::try_new(rhs)?, }, )) } @@ -205,14 +205,15 @@ fn lit(c: &mut Ctxt<'_, '_>, span: Span, hir: hir::Lit<'_>) -> compile::Result ir::Ir::new(span, ir::Value::Bool(boolean)), hir::Lit::Str(string) => ir::Ir::new( span, - ir::Value::String(Shared::new(string.to_owned()).with_span(span)?), + ir::Value::String(Shared::new(string.try_to_owned()?).with_span(span)?), ), hir::Lit::Integer(n) => ir::Ir::new(span, ir::Value::Integer(n)), hir::Lit::Float(n) => ir::Ir::new(span, ir::Value::Float(n)), hir::Lit::Byte(b) => ir::Ir::new(span, ir::Value::Byte(b)), hir::Lit::ByteStr(byte_str) => { - let value = - ir::Value::Bytes(Shared::new(Bytes::from_vec(byte_str.to_vec())).with_span(span)?); + let value = ir::Value::Bytes( + Shared::new(Bytes::from_vec(Vec::try_from(byte_str)?)).with_span(span)?, + ); ir::Ir::new(span, value) } hir::Lit::Char(c) => ir::Ir::new(span, ir::Value::Char(c)), @@ -228,14 +229,14 @@ fn expr_tuple(c: &mut Ctxt<'_, '_>, span: Span, hir: &hir::ExprSeq<'_>) -> compi let mut items = Vec::new(); for e in hir.items { - items.push(expr(e, c)?); + items.try_push(expr(e, c)?)?; } Ok(ir::Ir::new( span, ir::Tuple { span, - items: items.into_boxed_slice(), + items: items.try_into_boxed_slice()?, }, )) } @@ -249,12 +250,12 @@ fn expr_vec( let mut items = Vec::new(); for e in hir.items { - items.push(expr(e, c)?); + items.try_push(expr(e, c)?)?; } Ok(ir::IrVec { span, - items: items.into_boxed_slice(), + items: items.try_into_boxed_slice()?, }) } @@ -269,12 +270,12 @@ fn expr_object( for assign in hir.assignments { let (_, key) = assign.key; let ir = expr(&assign.assign, c)?; - assignments.push((key.into(), ir)) + assignments.try_push((key.try_into()?, ir))? } Ok(ir::IrObject { span, - assignments: assignments.into_boxed_slice(), + assignments: assignments.try_into_boxed_slice()?, }) } @@ -289,10 +290,10 @@ pub(crate) fn block(hir: &hir::Block<'_>, c: &mut Ctxt<'_, '_>) -> compile::Resu let (e, term) = match stmt { hir::Stmt::Local(l) => { if let Some((e, _)) = take(&mut last) { - instructions.push(expr(e, c)?); + instructions.try_push(expr(e, c)?)?; } - instructions.push(local(l, c)?); + instructions.try_push(local(l, c)?)?; continue; } hir::Stmt::Expr(e) => (e, false), @@ -301,16 +302,16 @@ pub(crate) fn block(hir: &hir::Block<'_>, c: &mut Ctxt<'_, '_>) -> compile::Resu }; if let Some((e, _)) = replace(&mut last, Some((e, term))) { - instructions.push(expr(e, c)?); + instructions.try_push(expr(e, c)?)?; } } let last = if let Some((e, term)) = last { if term { - instructions.push(expr(e, c)?); + instructions.try_push(expr(e, c)?)?; None } else { - Some(Box::new(expr(e, c)?)) + Some(Box::try_new(expr(e, c)?)?) } } else { None @@ -333,12 +334,12 @@ fn builtin_template( for e in template.exprs { if let hir::ExprKind::Lit(hir::Lit::Str(s)) = e.kind { - components.push(ir::IrTemplateComponent::String(s.into())); + components.try_push(ir::IrTemplateComponent::String(s.try_into()?))?; continue; } let ir = expr(e, c)?; - components.push(ir::IrTemplateComponent::Ir(ir)); + components.try_push(ir::IrTemplateComponent::Ir(ir))?; } Ok(ir::IrTemplate { span, components }) @@ -362,8 +363,8 @@ fn local(hir: &hir::Local<'_>, c: &mut Ctxt<'_, '_>) -> compile::Result span, ir::IrDecl { span, - name: hir::Name::Str(name).into_owned(), - value: Box::new(expr(&hir.expr, c)?), + name: hir::Name::Str(name).into_owned()?, + value: Box::try_new(expr(&hir.expr, c)?)?, }, )) } @@ -403,7 +404,7 @@ fn expr_if( let cond = condition(cond, c)?; let ir = block(&hir.block, c)?; - branches.push((cond, ir)); + branches.try_push((cond, ir))?; } Ok(ir::IrBranches { @@ -421,9 +422,9 @@ fn expr_loop( ) -> compile::Result { Ok(ir::IrLoop { span, - label: hir.label.map(|l| l.into()), + label: hir.label.map(TryInto::try_into).transpose()?, condition: match hir.condition { - Some(hir) => Some(Box::new(condition(hir, c)?)), + Some(hir) => Some(Box::try_new(condition(hir, c)?)?), None => None, }, body: block(&hir.body, c)?, diff --git a/crates/rune/src/compile/ir/eval.rs b/crates/rune/src/compile/ir/eval.rs index d4ef0ebc1..756cbbdb6 100644 --- a/crates/rune/src/compile/ir/eval.rs +++ b/crates/rune/src/compile/ir/eval.rs @@ -1,9 +1,8 @@ -use core::fmt::Write; use core::ops::{Add, Mul, Shl, Shr, Sub}; -use crate::no_std::collections::HashMap; -use crate::no_std::prelude::*; - +use crate::alloc::fmt::TryWrite; +use crate::alloc::prelude::*; +use crate::alloc::{Box, HashMap, String, Vec}; use crate::ast::{Span, Spanned}; use crate::compile::ir; use crate::compile::{self, WithSpan}; @@ -143,8 +142,8 @@ fn eval_ir_binary( ) -> compile::Result> { let a = a.borrow_ref().with_span(span)?; let b = b.borrow_ref().with_span(span)?; - let mut a = String::from(&*a); - a.push_str(&b); + let mut a = (*a).try_clone()?; + a.try_push_str(&b)?; Ok(Shared::new(a).with_span(span)?) } } @@ -155,7 +154,7 @@ fn eval_ir_branches( used: Used, ) -> Result { for (ir_condition, branch) in &ir.branches { - let guard = interp.scopes.push(); + let guard = interp.scopes.push()?; let value = eval_ir_condition(ir_condition, interp, used)?; @@ -187,7 +186,7 @@ fn eval_ir_call( let mut args = Vec::new(); for arg in &ir.args { - args.push(eval_ir(arg, interp, used)?); + args.try_push(eval_ir(arg, interp, used)?)?; } Ok(interp.call_const_fn(ir, ir.id, args, used)?) @@ -229,7 +228,7 @@ fn eval_ir_loop( let span = ir.span(); interp.budget.take(span)?; - let guard = interp.scopes.push(); + let guard = interp.scopes.push()?; let value = loop { if let Some(condition) = &ir.condition { @@ -278,10 +277,10 @@ fn eval_ir_object( interp: &mut ir::Interpreter<'_, '_>, used: Used, ) -> Result { - let mut object = HashMap::with_capacity(ir.assignments.len()); + let mut object = HashMap::try_with_capacity(ir.assignments.len())?; for (key, value) in ir.assignments.iter() { - object.insert(key.as_ref().to_owned(), eval_ir(value, interp, used)?); + object.try_insert(key.as_ref().try_to_owned()?, eval_ir(value, interp, used)?)?; } Ok(ir::Value::Object(Shared::new(object).with_span(ir)?)) @@ -293,7 +292,7 @@ fn eval_ir_scope( used: Used, ) -> Result { interp.budget.take(ir)?; - let guard = interp.scopes.push(); + let guard = interp.scopes.push()?; for ir in &ir.instructions { let _ = eval_ir(ir, interp, used)?; @@ -332,25 +331,25 @@ fn eval_ir_template( for component in &ir.components { match component { ir::IrTemplateComponent::String(string) => { - buf.push_str(string); + buf.try_push_str(string)?; } ir::IrTemplateComponent::Ir(ir) => { let const_value = eval_ir(ir, interp, used)?; match const_value { ir::Value::Integer(integer) => { - write!(buf, "{}", integer).unwrap(); + write!(buf, "{}", integer)?; } ir::Value::Float(float) => { let mut buffer = ryu::Buffer::new(); - buf.push_str(buffer.format(float)); + buf.try_push_str(buffer.format(float))?; } ir::Value::Bool(b) => { - write!(buf, "{}", b).unwrap(); + write!(buf, "{}", b)?; } ir::Value::String(s) => { let s = s.borrow_ref().with_span(ir)?; - buf.push_str(&s); + buf.try_push_str(&s)?; } _ => { return Err(EvalOutcome::not_const(ir)); @@ -368,14 +367,14 @@ fn eval_ir_tuple( interp: &mut ir::Interpreter<'_, '_>, used: Used, ) -> Result { - let mut items = Vec::with_capacity(ir.items.len()); + let mut items = Vec::try_with_capacity(ir.items.len())?; for item in ir.items.iter() { - items.push(eval_ir(item, interp, used)?); + items.try_push(eval_ir(item, interp, used)?)?; } Ok(ir::Value::Tuple( - Shared::new(items.into_boxed_slice()).with_span(ir)?, + Shared::new(items.try_into_boxed_slice()?).with_span(ir)?, )) } @@ -384,10 +383,10 @@ fn eval_ir_vec( interp: &mut ir::Interpreter<'_, '_>, used: Used, ) -> Result { - let mut vec = Vec::with_capacity(ir.items.len()); + let mut vec = Vec::try_with_capacity(ir.items.len())?; for item in ir.items.iter() { - vec.push(eval_ir(item, interp, used)?); + vec.try_push(eval_ir(item, interp, used)?)?; } Ok(ir::Value::Vec(Shared::new(vec).with_span(ir)?)) @@ -410,7 +409,7 @@ pub(crate) fn eval_ir( ir::IrKind::Template(ir) => eval_ir_template(ir, interp, used), ir::IrKind::Name(name) => Ok(interp.resolve_var(ir, name, used)?), ir::IrKind::Target(target) => Ok(interp.scopes.get_target(target)?), - ir::IrKind::Value(value) => Ok(value.clone()), + ir::IrKind::Value(value) => Ok(value.try_clone()?), ir::IrKind::Branches(ir) => eval_ir_branches(ir, interp, used), ir::IrKind::Loop(ir) => eval_ir_loop(ir, interp, used), ir::IrKind::Break(ir) => Err(ir.as_outcome(interp, used)), diff --git a/crates/rune/src/compile/ir/interpreter.rs b/crates/rune/src/compile/ir/interpreter.rs index fc0de48c2..0e8c9da0f 100644 --- a/crates/rune/src/compile/ir/interpreter.rs +++ b/crates/rune/src/compile/ir/interpreter.rs @@ -1,5 +1,5 @@ -use crate::no_std::prelude::*; - +use crate::alloc::prelude::*; +use crate::alloc::{try_format, Vec}; use crate::ast::Spanned; use crate::compile::ir; use crate::compile::ir::scopes::MissingLocal; @@ -31,10 +31,10 @@ impl Interpreter<'_, '_> { tracing::trace!("processing constant: {}", self.q.pool.item(self.item)); if let Some(const_value) = self.q.consts.get(self.item) { - return Ok(const_value.clone()); + return Ok(const_value.try_clone()?); } - if !self.q.consts.mark(self.item) { + if !self.q.consts.mark(self.item)? { return Err(compile::Error::new(ir, IrErrorKind::ConstCycle)); } @@ -58,7 +58,7 @@ impl Interpreter<'_, '_> { if self .q .consts - .insert(self.item, const_value.clone()) + .insert(self.item, const_value.try_clone()?)? .is_some() { return Err(compile::Error::new(ir, IrErrorKind::ConstCycle)); @@ -94,13 +94,16 @@ impl Interpreter<'_, '_> { used: Used, ) -> compile::Result { if let Some(ir_value) = self.scopes.try_get(name) { - return Ok(ir_value.clone()); + return Ok(ir_value.try_clone()?); } - let mut base = self.q.pool.item(self.item).to_owned(); + let mut base = self.q.pool.item(self.item).try_to_owned()?; loop { - let item = self.q.pool.alloc_item(base.extended(name.to_string())); + let item = self + .q + .pool + .alloc_item(base.extended(name.try_to_string()?)?)?; if let Some(const_value) = self.q.consts.get(item) { return Ok(ir::Value::from_const(const_value).with_span(span)?); @@ -112,7 +115,7 @@ impl Interpreter<'_, '_> { let Some(const_value) = self.q.get_const_value(meta.hash) else { return Err(compile::Error::msg( span, - format_args!("Missing constant for hash {}", meta.hash), + try_format!("Missing constant for hash {}", meta.hash), )); }; @@ -122,7 +125,7 @@ impl Interpreter<'_, '_> { return Err(compile::Error::new( span, IrErrorKind::UnsupportedMeta { - meta: meta.info(self.q.pool), + meta: meta.info(self.q.pool)?, }, )); } @@ -133,16 +136,19 @@ impl Interpreter<'_, '_> { break; } - base.pop(); + base.pop()?; } if name.as_ref().starts_with(char::is_lowercase) { - Err(compile::Error::new(span, MissingLocal(name.clone()))) + Err(compile::Error::new( + span, + MissingLocal(name.try_to_string()?.try_into_boxed_str()?), + )) } else { Err(compile::Error::new( span, IrErrorKind::MissingConst { - name: name.to_string().into(), + name: name.try_to_string()?.try_into()?, }, )) } @@ -171,7 +177,7 @@ impl Interpreter<'_, '_> { )); } - let guard = self.scopes.isolate(); + let guard = self.scopes.isolate()?; for (name, value) in const_fn.ir_fn.args.iter().zip(args) { self.scopes.decl(name, value).with_span(span)?; @@ -187,7 +193,7 @@ impl ir::Scopes { /// Get the given target as mut. pub(crate) fn get_target(&mut self, ir_target: &ir::IrTarget) -> compile::Result { match &ir_target.kind { - ir::IrTargetKind::Name(name) => Ok(self.get_name(name).with_span(ir_target)?.clone()), + ir::IrTargetKind::Name(name) => Ok(self.get_name(name, ir_target)?.try_clone()?), ir::IrTargetKind::Field(ir_target, field) => { let value = self.get_target(ir_target)?; @@ -195,7 +201,7 @@ impl ir::Scopes { ir::Value::Object(object) => { let object = object.borrow_ref().with_span(ir_target)?; - if let Some(value) = object.get(field.as_ref()).cloned() { + if let Some(value) = object.get(field.as_ref()).try_cloned()? { return Ok(value); } } @@ -209,7 +215,7 @@ impl ir::Scopes { Err(compile::Error::new( ir_target, IrErrorKind::MissingField { - field: field.clone(), + field: field.try_clone()?, }, )) } @@ -220,14 +226,14 @@ impl ir::Scopes { ir::Value::Vec(vec) => { let vec = vec.borrow_ref().with_span(ir_target)?; - if let Some(value) = vec.get(*index).cloned() { + if let Some(value) = vec.get(*index).try_cloned()? { return Ok(value); } } ir::Value::Tuple(tuple) => { let tuple = tuple.borrow_ref().with_span(ir_target)?; - if let Some(value) = tuple.get(*index).cloned() { + if let Some(value) = tuple.get(*index).try_cloned()? { return Ok(value); } } @@ -254,7 +260,7 @@ impl ir::Scopes { ) -> compile::Result<()> { match &ir_target.kind { ir::IrTargetKind::Name(name) => { - *self.get_name_mut(name).with_span(ir_target)? = value; + *self.get_name_mut(name, ir_target)? = value; Ok(()) } ir::IrTargetKind::Field(target, field) => { @@ -263,7 +269,7 @@ impl ir::Scopes { match current { ir::Value::Object(object) => { let mut object = object.borrow_mut().with_span(ir_target)?; - object.insert(field.as_ref().to_owned(), value); + object.try_insert(field.as_ref().try_to_owned()?, value)?; } actual => { return Err(compile::Error::expected_type::<_, Object>( @@ -314,7 +320,7 @@ impl ir::Scopes { ) -> compile::Result<()> { match &ir_target.kind { ir::IrTargetKind::Name(name) => { - let value = self.get_name_mut(name).with_span(ir_target)?; + let value = self.get_name_mut(name, ir_target)?; op(value) } ir::IrTargetKind::Field(target, field) => { @@ -324,14 +330,14 @@ impl ir::Scopes { ir::Value::Object(object) => { let mut object = object.borrow_mut().with_span(ir_target)?; - let value = object.get_mut(field.as_ref()).ok_or_else(|| { - compile::Error::new( + let Some(value) = object.get_mut(field.as_ref()) else { + return Err(compile::Error::new( ir_target, IrErrorKind::MissingField { - field: field.clone(), + field: field.try_clone()?, }, - ) - })?; + )); + }; op(value) } diff --git a/crates/rune/src/compile/ir/scopes.rs b/crates/rune/src/compile/ir/scopes.rs index a6b22b4d9..66b35db2c 100644 --- a/crates/rune/src/compile/ir/scopes.rs +++ b/crates/rune/src/compile/ir/scopes.rs @@ -1,11 +1,12 @@ -use crate::no_std::collections::HashMap; -use crate::no_std::prelude::*; - +use crate::alloc::prelude::*; +use crate::alloc::{self, try_vec, Box, HashMap, Vec}; +use crate::ast::Spanned; use crate::compile::ir; +use crate::compile::{self, ErrorKind}; use crate::hir; /// Error indicating that a local variable is missing. -pub(crate) struct MissingLocal(pub(crate) hir::OwnedName); +pub(crate) struct MissingLocal(pub(crate) Box); /// A hierarchy of constant scopes. pub(crate) struct Scopes { @@ -13,6 +14,13 @@ pub(crate) struct Scopes { } impl Scopes { + /// Construct a new empty scope. + pub(crate) fn new() -> alloc::Result { + Ok(Self { + scopes: try_vec![Scope::default()], + }) + } + /// Clear the current scope. pub(crate) fn clear_current(&mut self) -> Result<(), &'static str> { let last = self @@ -29,9 +37,11 @@ impl Scopes { &mut self, name: &hir::OwnedName, value: ir::Value, - ) -> Result<(), &'static str> { - let last = self.last_mut().ok_or("expected at least one scope")?; - last.locals.insert(name.clone(), value); + ) -> Result<(), ErrorKind> { + let last = self + .last_mut() + .ok_or_else(|| ErrorKind::msg("Expected at least one scope"))?; + last.locals.try_insert(name.try_clone()?, value)?; Ok(()) } @@ -52,7 +62,11 @@ impl Scopes { } /// Get the given variable. - pub(crate) fn get_name(&self, name: &hir::OwnedName) -> Result<&ir::Value, MissingLocal> { + pub(crate) fn get_name( + &self, + name: &hir::OwnedName, + span: &dyn Spanned, + ) -> compile::Result<&ir::Value> { for scope in self.scopes.iter().rev() { if let Some(current) = scope.locals.get(name) { return Ok(current); @@ -64,14 +78,18 @@ impl Scopes { } } - Err(MissingLocal(name.clone())) + Err(compile::Error::new( + span, + MissingLocal(name.try_to_string()?.try_into_boxed_str()?), + )) } /// Get the given variable as mutable. pub(crate) fn get_name_mut( &mut self, name: &hir::OwnedName, - ) -> Result<&mut ir::Value, MissingLocal> { + span: &dyn Spanned, + ) -> compile::Result<&mut ir::Value> { for scope in self.scopes.iter_mut().rev() { if let Some(current) = scope.locals.get_mut(name) { return Ok(current); @@ -83,25 +101,28 @@ impl Scopes { } } - Err(MissingLocal(name.clone())) + Err(compile::Error::new( + span, + MissingLocal(name.try_to_string()?.try_into_boxed_str()?), + )) } /// Push a scope and return the guard associated with the scope. - pub(crate) fn push(&mut self) -> ScopeGuard { + pub(crate) fn push(&mut self) -> alloc::Result { let length = self.scopes.len(); - self.scopes.push(Scope::default()); - ScopeGuard { length } + self.scopes.try_push(Scope::default())?; + Ok(ScopeGuard { length }) } /// Push an isolate scope and return the guard associated with the scope. - pub(crate) fn isolate(&mut self) -> ScopeGuard { + pub(crate) fn isolate(&mut self) -> alloc::Result { let length = self.scopes.len(); let scope = Scope { kind: ScopeKind::Isolate, ..Default::default() }; - self.scopes.push(scope); - ScopeGuard { length } + self.scopes.try_push(scope)?; + Ok(ScopeGuard { length }) } pub(crate) fn pop(&mut self, guard: ScopeGuard) -> Result<(), &'static str> { @@ -122,14 +143,6 @@ impl Scopes { } } -impl Default for Scopes { - fn default() -> Self { - Self { - scopes: vec![Scope::default()], - } - } -} - #[repr(transparent)] pub(crate) struct ScopeGuard { length: usize, @@ -151,7 +164,7 @@ impl Default for Scope { fn default() -> Self { Self { kind: ScopeKind::None, - locals: Default::default(), + locals: HashMap::new(), } } } diff --git a/crates/rune/src/compile/ir/value.rs b/crates/rune/src/compile/ir/value.rs index 5b95446f5..8de31a002 100644 --- a/crates/rune/src/compile/ir/value.rs +++ b/crates/rune/src/compile/ir/value.rs @@ -1,14 +1,13 @@ -use crate::no_std::collections::HashMap; -use crate::no_std::prelude::*; - -use crate::alloc::Error; +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, HashMap, String, Vec}; use crate::ast::Spanned; use crate::compile::{self, WithSpan}; use crate::runtime as rt; use crate::runtime::{Bytes, ConstValue, Shared, TypeInfo}; /// A constant value. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub enum Value { /// A constant unit. EmptyTuple, @@ -57,7 +56,7 @@ impl Value { } /// Convert a constant value into an interpreter value. - pub(crate) fn from_const(value: &ConstValue) -> Result { + pub(crate) fn from_const(value: &ConstValue) -> alloc::Result { Ok(match value { ConstValue::EmptyTuple => Self::EmptyTuple, ConstValue::Byte(b) => Self::Byte(*b), @@ -65,35 +64,35 @@ impl Value { ConstValue::Bool(b) => Self::Bool(*b), ConstValue::Integer(n) => Self::Integer(*n), ConstValue::Float(n) => Self::Float(*n), - ConstValue::String(s) => Self::String(Shared::new(s.clone())?), - ConstValue::Bytes(b) => Self::Bytes(Shared::new(b.clone())?), + ConstValue::String(s) => Self::String(Shared::new(s.try_clone()?)?), + ConstValue::Bytes(b) => Self::Bytes(Shared::new(b.try_clone()?)?), ConstValue::Option(option) => Self::Option(Shared::new(match option { Some(some) => Some(Self::from_const(some)?), None => None, })?), ConstValue::Vec(vec) => { - let mut ir_vec = Vec::with_capacity(vec.len()); + let mut ir_vec = Vec::try_with_capacity(vec.len())?; for value in vec { - ir_vec.push(Self::from_const(value)?); + ir_vec.try_push(Self::from_const(value)?)?; } Self::Vec(Shared::new(ir_vec)?) } ConstValue::Tuple(tuple) => { - let mut ir_tuple = Vec::with_capacity(tuple.len()); + let mut ir_tuple = Vec::try_with_capacity(tuple.len())?; for value in tuple.iter() { - ir_tuple.push(Self::from_const(value)?); + ir_tuple.try_push(Self::from_const(value)?)?; } - Self::Tuple(Shared::new(ir_tuple.into_boxed_slice())?) + Self::Tuple(Shared::new(ir_tuple.try_into_boxed_slice()?)?) } ConstValue::Object(object) => { - let mut ir_object = HashMap::with_capacity(object.len()); + let mut ir_object = HashMap::try_with_capacity(object.len())?; for (key, value) in object { - ir_object.insert(key.clone(), Self::from_const(value)?); + ir_object.try_insert(key.try_clone()?, Self::from_const(value)?)?; } Self::Object(Shared::new(ir_object)?) @@ -122,35 +121,35 @@ impl Value { ConstValue::Bytes(b) } Self::Option(option) => ConstValue::Option(match option.take().with_span(spanned)? { - Some(value) => Some(Box::new(value.into_const(spanned)?)), + Some(value) => Some(Box::try_new(value.into_const(spanned)?)?), None => None, }), Value::Vec(vec) => { let vec = vec.take().with_span(spanned)?; - let mut const_vec = Vec::with_capacity(vec.len()); + let mut const_vec = Vec::try_with_capacity(vec.len())?; for value in vec { - const_vec.push(value.into_const(spanned)?); + const_vec.try_push(value.into_const(spanned)?)?; } ConstValue::Vec(const_vec) } Value::Tuple(tuple) => { let tuple = tuple.take().with_span(spanned)?; - let mut const_tuple = Vec::with_capacity(tuple.len()); + let mut const_tuple = Vec::try_with_capacity(tuple.len())?; for value in Vec::from(tuple) { - const_tuple.push(value.into_const(spanned)?); + const_tuple.try_push(value.into_const(spanned)?)?; } - ConstValue::Tuple(const_tuple.into_boxed_slice()) + ConstValue::Tuple(const_tuple.try_into_boxed_slice()?) } Value::Object(object) => { let object = object.take().with_span(spanned)?; - let mut const_object = HashMap::with_capacity(object.len()); + let mut const_object = HashMap::try_with_capacity(object.len())?; for (key, value) in object { - const_object.insert(key, value.into_const(spanned)?); + const_object.try_insert(key, value.into_const(spanned)?)?; } ConstValue::Object(const_object) diff --git a/crates/rune/src/compile/location.rs b/crates/rune/src/compile/location.rs index baa1a7c6f..0d6adc04d 100644 --- a/crates/rune/src/compile/location.rs +++ b/crates/rune/src/compile/location.rs @@ -1,11 +1,14 @@ use core::fmt; +use crate as rune; +use crate::alloc::prelude::*; use crate::ast::{Span, Spanned}; use crate::SourceId; /// A fully descriptive location which is a combination of a [SourceId] and a /// [Span]. -#[derive(Default, Clone, Copy)] +#[derive(Default, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub struct Location { /// The source id of the file of the location. diff --git a/crates/rune/src/compile/meta.rs b/crates/rune/src/compile/meta.rs index 317be7e82..b5e6067b4 100644 --- a/crates/rune/src/compile/meta.rs +++ b/crates/rune/src/compile/meta.rs @@ -2,12 +2,11 @@ use core::fmt; -use crate::no_std::borrow::Cow; -use crate::no_std::collections::HashMap; -use crate::no_std::path::Path; -use crate::no_std::prelude::*; - use crate as rune; +use crate::alloc::borrow::Cow; +use crate::alloc::path::Path; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, HashMap, Vec}; use crate::ast; use crate::ast::{Span, Spanned}; use crate::compile::attrs::Parser; @@ -17,7 +16,8 @@ use crate::parse::{NonZeroId, ResolveContext}; use crate::runtime::{Call, Protocol}; /// A meta reference to an item being compiled. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub struct MetaRef<'a> { /// If the meta comes from the context or not. @@ -33,7 +33,7 @@ pub struct MetaRef<'a> { } /// Information on a compile sourc. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] #[non_exhaustive] pub struct SourceMeta { /// The location of the compile source. @@ -43,7 +43,8 @@ pub struct SourceMeta { } /// Doc content for a compiled item. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] pub(crate) struct Doc { #[rune(span)] pub(crate) span: Span, @@ -65,14 +66,14 @@ impl Doc { doc_string: doc.doc_string, }) }) - .collect::>()?; + .try_collect::>()??; Ok(docs) } } /// Metadata about a compiled unit. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] #[non_exhaustive] pub(crate) struct Meta { /// If the meta comes from the context or not. @@ -91,7 +92,7 @@ pub(crate) struct Meta { impl Meta { /// Get the [Meta] which describes metadata. - pub(crate) fn info(&self, pool: &Pool) -> MetaInfo { + pub(crate) fn info(&self, pool: &Pool) -> alloc::Result { MetaInfo::new(&self.kind, self.hash, Some(pool.item(self.item_meta.item))) } @@ -131,7 +132,7 @@ impl Meta { } /// The kind of a variant. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub enum Fields { /// Named fields. Named(FieldsNamed), @@ -142,7 +143,7 @@ pub enum Fields { } /// Compile-time metadata kind about a unit. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] #[non_exhaustive] pub enum Kind { /// The type is completely opaque. We have no idea about what it is with the @@ -262,7 +263,8 @@ impl Kind { } /// An imported entry. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub struct Import { /// The location of the import. @@ -274,7 +276,7 @@ pub struct Import { } /// Metadata about named fields. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] #[non_exhaustive] pub struct FieldsNamed { /// Fields associated with the type. @@ -282,14 +284,15 @@ pub struct FieldsNamed { } /// Metadata for a single named field. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub struct FieldMeta { /// Position of the field in its containing type declaration. pub(crate) position: usize, } /// Item and the module that the item belongs to. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ItemMeta { /// The id of the item. @@ -312,7 +315,7 @@ impl ItemMeta { } /// A description of a function signature. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub struct Signature { /// An asynchronous function. #[cfg(feature = "doc")] @@ -332,7 +335,7 @@ pub struct Signature { } /// The kind of an associated function. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, TryClone, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum AssociatedKind { /// A protocol function implemented on the type itself. diff --git a/crates/rune/src/compile/meta_info.rs b/crates/rune/src/compile/meta_info.rs index ecd78d11e..198ae364b 100644 --- a/crates/rune/src/compile/meta_info.rs +++ b/crates/rune/src/compile/meta_info.rs @@ -1,12 +1,12 @@ use core::fmt; -use crate::no_std::prelude::*; - +use crate::alloc; +use crate::alloc::prelude::*; use crate::compile::{meta, Item, ItemBuf}; use crate::Hash; /// Provides an owned human-readable description of a meta item. -#[derive(Debug, Clone)] +#[derive(Debug)] #[non_exhaustive] pub struct MetaInfo { /// The kind of the item. @@ -19,12 +19,12 @@ pub struct MetaInfo { impl MetaInfo { /// Construct a new meta info. - pub(crate) fn new(kind: &meta::Kind, hash: Hash, item: Option<&Item>) -> Self { - Self { + pub(crate) fn new(kind: &meta::Kind, hash: Hash, item: Option<&Item>) -> alloc::Result { + Ok(Self { kind: MetaInfoKind::from_kind(kind), hash, - item: item.map(|item| item.to_owned()), - } + item: item.map(|item| item.try_to_owned()).transpose()?, + }) } } diff --git a/crates/rune/src/compile/named.rs b/crates/rune/src/compile/named.rs index 686d3a5dc..2a0a15a7d 100644 --- a/crates/rune/src/compile/named.rs +++ b/crates/rune/src/compile/named.rs @@ -2,7 +2,6 @@ use core::cmp::Ordering; use crate::alloc::String; use crate::module::InstallWith; -use crate::no_std::boxed::Box; use crate::runtime::RawStr; /// The trait used for something that can be statically named. @@ -11,7 +10,7 @@ pub trait Named { const BASE_NAME: RawStr; /// The exact type name - fn full_name() -> Box { + fn full_name() -> ::rust_alloc::boxed::Box { (*Self::BASE_NAME).into() } } diff --git a/crates/rune/src/compile/names.rs b/crates/rune/src/compile/names.rs index d8fdf6b34..65fd2c043 100644 --- a/crates/rune/src/compile/names.rs +++ b/crates/rune/src/compile/names.rs @@ -1,6 +1,8 @@ use core::mem::replace; -use crate::alloc::{AllocError, BTreeMap, Error, TryClone}; +use crate::alloc; +use crate::alloc::btree_map::{self, BTreeMap}; +use crate::alloc::prelude::*; use crate::compile::{Component, ComponentRef, IntoComponent}; /// A tree of names. @@ -10,7 +12,7 @@ pub struct Names { } impl TryClone for Names { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { root: self.root.try_clone()?, }) @@ -19,7 +21,7 @@ impl TryClone for Names { impl Names { /// Insert the given item as an import. - pub(crate) fn insert(&mut self, iter: I) -> Result + pub(crate) fn insert(&mut self, iter: I) -> alloc::Result where I: IntoIterator, I::Item: IntoComponent, @@ -29,7 +31,7 @@ impl Names { for c in iter { current = current .children - .entry(c.into_component()) + .entry(c.into_component()?) .or_try_default()?; } @@ -37,21 +39,21 @@ impl Names { } /// Test if the given import exists. - pub(crate) fn contains(&self, iter: I) -> bool + pub(crate) fn contains(&self, iter: I) -> alloc::Result where I: IntoIterator, I::Item: IntoComponent, { - self.find_node(iter).map(|n| n.term).unwrap_or_default() + Ok(self.find_node(iter)?.map(|n| n.term).unwrap_or_default()) } /// Test if we contain the given prefix. - pub(crate) fn contains_prefix(&self, iter: I) -> bool + pub(crate) fn contains_prefix(&self, iter: I) -> alloc::Result where I: IntoIterator, I::Item: IntoComponent, { - self.find_node(iter).is_some() + Ok(self.find_node(iter)?.is_some()) } /// Iterate over all known components immediately under the specified `iter` @@ -59,43 +61,22 @@ impl Names { pub(crate) fn iter_components<'a, I: 'a>( &'a self, iter: I, - ) -> impl Iterator> + 'a + ) -> alloc::Result> + 'a> where I: IntoIterator, I::Item: IntoComponent, { - let mut current = &self.root; - - for c in iter { - let c = c.into_component(); - - current = match current.children.get(&c) { - Some(node) => node, - None => return IterComponents(None), - }; - } - - return IterComponents(Some(current.children.keys())); + let iter = if let Some(current) = self.find_node(iter)? { + current.children.keys() + } else { + btree_map::Keys::default() + }; - struct IterComponents(Option); - - impl<'a, I> Iterator for IterComponents - where - I: Iterator, - { - type Item = ComponentRef<'a>; - - fn next(&mut self) -> Option { - let mut iter = self.0.take()?; - let next = iter.next()?; - self.0 = Some(iter); - Some(next.as_component_ref()) - } - } + Ok(iter.map(|c| c.as_component_ref())) } /// Find the node corresponding to the given path. - fn find_node(&self, iter: I) -> Option<&Node> + fn find_node(&self, iter: I) -> alloc::Result> where I: IntoIterator, I::Item: IntoComponent, @@ -103,11 +84,16 @@ impl Names { let mut current = &self.root; for c in iter { - let c = c.as_component_ref().into_component(); - current = current.children.get(&c)?; + let c = c.into_component()?; + + let Some(c) = current.children.get(&c) else { + return Ok(None); + }; + + current = c; } - Some(current) + Ok(Some(current)) } } @@ -120,7 +106,7 @@ struct Node { } impl TryClone for Node { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { term: self.term, children: self.children.try_clone()?, @@ -131,22 +117,25 @@ impl TryClone for Node { #[cfg(test)] mod tests { use super::Names; + use crate::support::Result; #[test] - fn insert() { + fn insert() -> Result<()> { let mut names = Names::default(); - assert!(!names.contains(["test"])); + assert!(!names.contains(["test"])?); assert!(!names.insert(["test"]).unwrap()); - assert!(names.contains(["test"])); + assert!(names.contains(["test"])?); assert!(names.insert(["test"]).unwrap()); + Ok(()) } #[test] - fn contains() { + fn contains() -> Result<()> { let mut names = Names::default(); - assert!(!names.contains(["test"])); + assert!(!names.contains(["test"])?); assert!(!names.insert(["test"]).unwrap()); - assert!(names.contains(["test"])); + assert!(names.contains(["test"])?); assert!(names.insert(["test"]).unwrap()); + Ok(()) } } diff --git a/crates/rune/src/compile/pool.rs b/crates/rune/src/compile/pool.rs index 67717392e..ee2c966dc 100644 --- a/crates/rune/src/compile/pool.rs +++ b/crates/rune/src/compile/pool.rs @@ -1,16 +1,17 @@ -use crate::no_std::prelude::*; - use core::fmt; -use crate::no_std::collections::HashMap; - +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::try_vec; +use crate::alloc::{self, HashMap, Vec}; #[cfg(feature = "emit")] use crate::compile::Location; use crate::compile::{Item, ItemBuf, Visibility}; use crate::hash::Hash; /// The identifier of a module. -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Default, Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[repr(transparent)] pub(crate) struct ModId(u32); @@ -21,7 +22,8 @@ impl fmt::Display for ModId { } /// The identifier of an item. -#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Default, Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] #[repr(transparent)] pub(crate) struct ItemId(u32); @@ -72,9 +74,9 @@ macro_rules! alloc_item { Some(id) => *id, None => { let id = ItemId(u32::try_from($self.items.len()).expect("ran out of item ids")); - let item = $item.to_owned(); - $self.items.push(ItemStorage { hash, item }); - $self.hash_to_item.insert(hash, id); + let item = $item.try_to_owned()?; + $self.items.try_push(ItemStorage { hash, item })?; + $self.hash_to_item.try_insert(hash, id)?; id } } @@ -95,6 +97,20 @@ pub(crate) struct Pool { } impl Pool { + pub fn new() -> alloc::Result { + let root_hash: Hash = Hash::type_hash(Item::new()); + + Ok(Self { + modules: Vec::new(), + items: try_vec![ItemStorage { + hash: root_hash, + item: ItemBuf::new(), + }], + item_to_mod: HashMap::new(), + hash_to_item: HashMap::try_from_iter([(root_hash, ItemId(0))])?, + }) + } + /// Lookup an item by the given identifier. pub(crate) fn item(&self, id: ItemId) -> &Item { &self.item_storage(id).item @@ -133,32 +149,35 @@ impl Pool { } /// Allocate or return an existing module identifier. - pub(crate) fn alloc_module(&mut self, item: ModMeta) -> ModId { + pub(crate) fn alloc_module(&mut self, item: ModMeta) -> alloc::Result { if let Some(id) = self.item_to_mod.get(&item.item) { - return *id; + return Ok(*id); } let id = ModId(u32::try_from(self.modules.len()).expect("ran out of item ids")); - self.item_to_mod.insert(item.item, id); - self.modules.push(item); - id + self.item_to_mod.try_insert(item.item, id)?; + self.modules.try_push(item)?; + Ok(id) } /// Allocate or return an existing item. - pub(crate) fn alloc_item(&mut self, item: T) -> ItemId + pub(crate) fn alloc_item(&mut self, item: T) -> alloc::Result where T: AsRef, { - alloc_item!(self, item.as_ref()) + Ok(alloc_item!(self, item.as_ref())) } /// Map a value into a new item. - pub(crate) fn try_map_alloc(&mut self, id: ItemId, m: M) -> Option + pub(crate) fn try_map_alloc(&mut self, id: ItemId, m: M) -> alloc::Result> where M: FnOnce(&Item) -> Option<&Item>, { - let item = m(self.item(id))?; - Some(alloc_item!(self, item)) + let Some(item) = m(self.item(id)) else { + return Ok(None); + }; + + Ok(Some(alloc_item!(self, item))) } fn item_storage(&self, ItemId(id): ItemId) -> &ItemStorage { @@ -170,19 +189,3 @@ impl Pool { } } } - -impl Default for Pool { - fn default() -> Self { - let root_hash: Hash = Hash::type_hash(Item::new()); - - Self { - modules: Default::default(), - items: vec![ItemStorage { - hash: root_hash, - item: ItemBuf::new(), - }], - item_to_mod: Default::default(), - hash_to_item: HashMap::from_iter([(root_hash, ItemId(0))]), - } - } -} diff --git a/crates/rune/src/compile/prelude.rs b/crates/rune/src/compile/prelude.rs index 900f7ddb3..a2caa6893 100644 --- a/crates/rune/src/compile/prelude.rs +++ b/crates/rune/src/compile/prelude.rs @@ -1,7 +1,4 @@ -use crate::no_std::prelude::*; - -use crate::no_std::collections::HashMap; - +use crate::alloc::{self, Box, HashMap}; use crate::compile::{IntoComponent, Item, ItemBuf}; /// The contents of a prelude. @@ -13,42 +10,42 @@ pub struct Prelude { impl Prelude { /// Construct a new unit with the default prelude. - pub(crate) fn with_default_prelude() -> Self { + pub(crate) fn with_default_prelude() -> alloc::Result { let mut this = Self::default(); - this.add_prelude("Type", ["any", "Type"]); - this.add_prelude("assert_eq", ["test", "assert_eq"]); - this.add_prelude("assert_ne", ["test", "assert_ne"]); - this.add_prelude("assert", ["test", "assert"]); - this.add_prelude("bool", ["bool"]); - this.add_prelude("u8", ["u8"]); - this.add_prelude("f64", ["f64"]); - this.add_prelude("i64", ["i64"]); - this.add_prelude("char", ["char"]); - this.add_prelude("dbg", ["io", "dbg"]); - this.add_prelude("drop", ["mem", "drop"]); - this.add_prelude("Err", ["result", "Result", "Err"]); - this.add_prelude("file", ["macros", "builtin", "file"]); - this.add_prelude("format", ["fmt", "format"]); - this.add_prelude("is_readable", ["is_readable"]); - this.add_prelude("is_writable", ["is_writable"]); - this.add_prelude("line", ["macros", "builtin", "line"]); - this.add_prelude("None", ["option", "Option", "None"]); - this.add_prelude("Tuple", ["tuple", "Tuple"]); - this.add_prelude("Object", ["object", "Object"]); - this.add_prelude("Ok", ["result", "Result", "Ok"]); - this.add_prelude("Option", ["option", "Option"]); - this.add_prelude("panic", ["panic"]); - this.add_prelude("print", ["io", "print"]); - this.add_prelude("println", ["io", "println"]); - this.add_prelude("Result", ["result", "Result"]); - this.add_prelude("Some", ["option", "Option", "Some"]); - this.add_prelude("String", ["string", "String"]); - this.add_prelude("stringify", ["stringify"]); - this.add_prelude("Vec", ["vec", "Vec"]); - this.add_prelude("Bytes", ["bytes", "Bytes"]); + this.add_prelude("Type", ["any", "Type"])?; + this.add_prelude("assert_eq", ["test", "assert_eq"])?; + this.add_prelude("assert_ne", ["test", "assert_ne"])?; + this.add_prelude("assert", ["test", "assert"])?; + this.add_prelude("bool", ["bool"])?; + this.add_prelude("u8", ["u8"])?; + this.add_prelude("f64", ["f64"])?; + this.add_prelude("i64", ["i64"])?; + this.add_prelude("char", ["char"])?; + this.add_prelude("dbg", ["io", "dbg"])?; + this.add_prelude("drop", ["mem", "drop"])?; + this.add_prelude("Err", ["result", "Result", "Err"])?; + this.add_prelude("file", ["macros", "builtin", "file"])?; + this.add_prelude("format", ["fmt", "format"])?; + this.add_prelude("is_readable", ["is_readable"])?; + this.add_prelude("is_writable", ["is_writable"])?; + this.add_prelude("line", ["macros", "builtin", "line"])?; + this.add_prelude("None", ["option", "Option", "None"])?; + this.add_prelude("Tuple", ["tuple", "Tuple"])?; + this.add_prelude("Object", ["object", "Object"])?; + this.add_prelude("Ok", ["result", "Result", "Ok"])?; + this.add_prelude("Option", ["option", "Option"])?; + this.add_prelude("panic", ["panic"])?; + this.add_prelude("print", ["io", "print"])?; + this.add_prelude("println", ["io", "println"])?; + this.add_prelude("Result", ["result", "Result"])?; + this.add_prelude("Some", ["option", "Option", "Some"])?; + this.add_prelude("String", ["string", "String"])?; + this.add_prelude("stringify", ["stringify"])?; + this.add_prelude("Vec", ["vec", "Vec"])?; + this.add_prelude("Bytes", ["bytes", "Bytes"])?; - this + Ok(this) } /// Access a value from the prelude. @@ -57,12 +54,13 @@ impl Prelude { } /// Define a prelude item. - fn add_prelude(&mut self, local: &str, path: I) + fn add_prelude(&mut self, local: &str, path: I) -> alloc::Result<()> where I: IntoIterator, I::Item: IntoComponent, { self.prelude - .insert(local.into(), ItemBuf::with_crate_item("std", path)); + .try_insert(local.try_into()?, ItemBuf::with_crate_item("std", path)?)?; + Ok(()) } } diff --git a/crates/rune/src/compile/source_loader.rs b/crates/rune/src/compile/source_loader.rs index 967c98f0f..487d6051f 100644 --- a/crates/rune/src/compile/source_loader.rs +++ b/crates/rune/src/compile/source_loader.rs @@ -1,6 +1,5 @@ -use crate::no_std::path::Path; -use crate::no_std::prelude::*; - +use crate::alloc::path::Path; +use crate::alloc::prelude::*; use crate::ast::Spanned; use crate::compile::{self, ComponentRef, ErrorKind, Item}; use crate::Source; @@ -36,13 +35,13 @@ impl FileSourceLoader { impl SourceLoader for FileSourceLoader { fn load(&mut self, root: &Path, item: &Item, span: &dyn Spanned) -> compile::Result { - let mut base = root.to_owned(); + let mut base = root.try_to_owned()?; if !base.pop() { return Err(compile::Error::new( span, ErrorKind::UnsupportedModuleRoot { - root: root.to_owned(), + root: root.try_to_owned()?, }, )); } @@ -54,7 +53,7 @@ impl SourceLoader for FileSourceLoader { return Err(compile::Error::new( span, ErrorKind::UnsupportedModuleItem { - item: item.to_owned(), + item: item.try_to_owned()?, }, )); } @@ -71,14 +70,11 @@ impl SourceLoader for FileSourceLoader { } } - let path = match found { - Some(path) => path, - None => { - return Err(compile::Error::new( - span, - ErrorKind::ModNotFound { path: base }, - )); - } + let Some(path) = found else { + return Err(compile::Error::new( + span, + ErrorKind::ModNotFound { path: base }, + )); }; match Source::from_path(path) { @@ -86,7 +82,7 @@ impl SourceLoader for FileSourceLoader { Err(error) => Err(compile::Error::new( span, ErrorKind::FileError { - path: path.to_owned(), + path: path.clone(), error, }, )), diff --git a/crates/rune/src/compile/unit_builder.rs b/crates/rune/src/compile/unit_builder.rs index 65ec79872..670348bc9 100644 --- a/crates/rune/src/compile/unit_builder.rs +++ b/crates/rune/src/compile/unit_builder.rs @@ -5,10 +5,11 @@ use core::fmt; -use crate::no_std::collections::HashMap; -use crate::no_std::prelude::*; use crate::no_std::sync::Arc; +use crate::alloc::fmt::TryWrite; +use crate::alloc::prelude::*; +use crate::alloc::{self, try_format, Box, HashMap, String, Vec}; use crate::ast::{Span, Spanned}; use crate::compile::meta; use crate::compile::{self, Assembly, AssemblyInst, ErrorKind, Item, Location, Pool, WithSpan}; @@ -37,7 +38,7 @@ impl fmt::Display for LinkerError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { LinkerError::MissingFunction { hash, .. } => { - write!(f, "Missing function with hash {hash}",) + write!(f, "Missing function with hash {hash}") } } } @@ -89,8 +90,10 @@ pub(crate) struct UnitBuilder { impl UnitBuilder { /// Insert an identifier for debug purposes. - pub(crate) fn insert_debug_ident(&mut self, ident: &str) { - self.hash_to_ident.insert(Hash::ident(ident), ident.into()); + pub(crate) fn insert_debug_ident(&mut self, ident: &str) -> alloc::Result<()> { + self.hash_to_ident + .try_insert(Hash::ident(ident), ident.try_into()?)?; + Ok(()) } /// Convert into a runtime unit, shedding our build metadata in the process. @@ -105,7 +108,12 @@ impl UnitBuilder { for (from, to) in self.reexports { if let Some(info) = self.functions.get(&to) { let info = *info; - if self.functions.insert(from, info).is_some() { + if self + .functions + .try_insert(from, info) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::FunctionConflictHash { hash: from }, @@ -115,9 +123,14 @@ impl UnitBuilder { } if let Some(value) = self.constants.get(&to) { - let const_value = value.clone(); - - if self.constants.insert(from, const_value).is_some() { + let const_value = value.try_clone()?; + + if self + .constants + .try_insert(from, const_value) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::ConstantConflict { hash: from }, @@ -155,27 +168,27 @@ impl UnitBuilder { span: &dyn Spanned, current: &str, ) -> compile::Result { - let current = StaticString::new(current); + let current = StaticString::new(current)?; let hash = current.hash(); if let Some(existing_slot) = self.static_string_rev.get(&hash).copied() { - let existing = self.static_strings.get(existing_slot).ok_or_else(|| { - compile::Error::new( + let Some(existing) = self.static_strings.get(existing_slot) else { + return Err(compile::Error::new( span, ErrorKind::StaticStringMissing { hash, slot: existing_slot, }, - ) - })?; + )); + }; if ***existing != *current { return Err(compile::Error::new( span, ErrorKind::StaticStringHashConflict { hash, - current: (*current).clone(), - existing: (***existing).clone(), + current: (*current).try_clone()?, + existing: (***existing).try_clone()?, }, )); } @@ -184,8 +197,8 @@ impl UnitBuilder { } let new_slot = self.static_strings.len(); - self.static_strings.push(Arc::new(current)); - self.static_string_rev.insert(hash, new_slot); + self.static_strings.try_push(Arc::new(current))?; + self.static_string_rev.try_insert(hash, new_slot)?; Ok(new_slot) } @@ -216,8 +229,8 @@ impl UnitBuilder { span, ErrorKind::StaticBytesHashConflict { hash, - current: current.to_owned(), - existing: existing.clone(), + current: current.try_to_owned()?, + existing: existing.try_clone()?, }, )); } @@ -226,8 +239,8 @@ impl UnitBuilder { } let new_slot = self.static_bytes.len(); - self.static_bytes.push(current.to_owned()); - self.static_bytes_rev.insert(hash, new_slot); + self.static_bytes.try_push(current.try_to_owned()?)?; + self.static_bytes_rev.try_insert(hash, new_slot)?; Ok(new_slot) } @@ -244,8 +257,8 @@ impl UnitBuilder { { let current = current .into_iter() - .map(|s| s.as_ref().to_owned()) - .collect::>(); + .map(|s| s.as_ref().try_to_owned()) + .try_collect::>>()??; self.new_static_object_keys(span, current) } @@ -276,7 +289,7 @@ impl UnitBuilder { ErrorKind::StaticObjectKeysHashConflict { hash, current, - existing: existing.clone(), + existing: existing.try_clone()?, }, )); } @@ -285,8 +298,8 @@ impl UnitBuilder { } let new_slot = self.static_object_keys.len(); - self.static_object_keys.push(current); - self.static_object_keys_rev.insert(hash, new_slot); + self.static_object_keys.try_push(current)?; + self.static_object_keys_rev.try_insert(hash, new_slot)?; Ok(new_slot) } @@ -304,15 +317,17 @@ impl UnitBuilder { let rtti = Arc::new(Rtti { hash, - item: pool.item(meta.item_meta.item).to_owned(), + item: pool.item(meta.item_meta.item).try_to_owned()?, }); - self.constants.insert( - Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), - ConstValue::String(rtti.item.to_string()), - ); + self.constants + .try_insert( + Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), + ConstValue::String(rtti.item.try_to_string()?), + ) + .with_span(span)?; - if self.rtti.insert(hash, rtti).is_some() { + if self.rtti.try_insert(hash, rtti).with_span(span)?.is_some() { return Err(compile::Error::new( span, ErrorKind::TypeRttiConflict { hash }, @@ -326,23 +341,33 @@ impl UnitBuilder { let info = UnitFn::EmptyStruct { hash: meta.hash }; let signature = DebugSignature::new( - pool.item(meta.item_meta.item).to_owned(), + pool.item(meta.item_meta.item).try_to_owned()?, DebugArgs::EmptyArgs, ); let rtti = Arc::new(Rtti { hash: meta.hash, - item: pool.item(meta.item_meta.item).to_owned(), + item: pool.item(meta.item_meta.item).try_to_owned()?, }); - if self.rtti.insert(meta.hash, rtti).is_some() { + if self + .rtti + .try_insert(meta.hash, rtti) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::TypeRttiConflict { hash: meta.hash }, )); } - if self.functions.insert(meta.hash, info).is_some() { + if self + .functions + .try_insert(meta.hash, info) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::FunctionConflict { @@ -351,12 +376,16 @@ impl UnitBuilder { )); } - self.constants.insert( - Hash::associated_function(meta.hash, Protocol::INTO_TYPE_NAME), - ConstValue::String(signature.path.to_string()), - ); + self.constants + .try_insert( + Hash::associated_function(meta.hash, Protocol::INTO_TYPE_NAME), + ConstValue::String(signature.path.try_to_string()?), + ) + .with_span(span)?; - self.debug_info_mut().functions.insert(meta.hash, signature); + self.debug_mut()? + .functions + .try_insert(meta.hash, signature)?; } meta::Kind::Struct { fields: meta::Fields::Unnamed(args), @@ -368,23 +397,33 @@ impl UnitBuilder { }; let signature = DebugSignature::new( - pool.item(meta.item_meta.item).to_owned(), + pool.item(meta.item_meta.item).try_to_owned()?, DebugArgs::TupleArgs(args), ); let rtti = Arc::new(Rtti { hash: meta.hash, - item: pool.item(meta.item_meta.item).to_owned(), + item: pool.item(meta.item_meta.item).try_to_owned()?, }); - if self.rtti.insert(meta.hash, rtti).is_some() { + if self + .rtti + .try_insert(meta.hash, rtti) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::TypeRttiConflict { hash: meta.hash }, )); } - if self.functions.insert(meta.hash, info).is_some() { + if self + .functions + .try_insert(meta.hash, info) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::FunctionConflict { @@ -393,27 +432,33 @@ impl UnitBuilder { )); } - self.constants.insert( - Hash::associated_function(meta.hash, Protocol::INTO_TYPE_NAME), - ConstValue::String(signature.path.to_string()), - ); + self.constants + .try_insert( + Hash::associated_function(meta.hash, Protocol::INTO_TYPE_NAME), + ConstValue::String(signature.path.try_to_string()?), + ) + .with_span(span)?; - self.debug_info_mut().functions.insert(meta.hash, signature); + self.debug_mut()? + .functions + .try_insert(meta.hash, signature)?; } meta::Kind::Struct { .. } => { let hash = pool.item_type_hash(meta.item_meta.item); let rtti = Arc::new(Rtti { hash, - item: pool.item(meta.item_meta.item).to_owned(), + item: pool.item(meta.item_meta.item).try_to_owned()?, }); - self.constants.insert( - Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), - ConstValue::String(rtti.item.to_string()), - ); + self.constants + .try_insert( + Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), + ConstValue::String(rtti.item.try_to_string()?), + ) + .with_span(span)?; - if self.rtti.insert(hash, rtti).is_some() { + if self.rtti.try_insert(hash, rtti).with_span(span)?.is_some() { return Err(compile::Error::new( span, ErrorKind::TypeRttiConflict { hash }, @@ -428,10 +473,15 @@ impl UnitBuilder { let rtti = Arc::new(VariantRtti { enum_hash, hash: meta.hash, - item: pool.item(meta.item_meta.item).to_owned(), + item: pool.item(meta.item_meta.item).try_to_owned()?, }); - if self.variant_rtti.insert(meta.hash, rtti).is_some() { + if self + .variant_rtti + .try_insert(meta.hash, rtti) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::VariantRttiConflict { hash: meta.hash }, @@ -441,11 +491,16 @@ impl UnitBuilder { let info = UnitFn::UnitVariant { hash: meta.hash }; let signature = DebugSignature::new( - pool.item(meta.item_meta.item).to_owned(), + pool.item(meta.item_meta.item).try_to_owned()?, DebugArgs::EmptyArgs, ); - if self.functions.insert(meta.hash, info).is_some() { + if self + .functions + .try_insert(meta.hash, info) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::FunctionConflict { @@ -454,7 +509,9 @@ impl UnitBuilder { )); } - self.debug_info_mut().functions.insert(meta.hash, signature); + self.debug_mut()? + .functions + .try_insert(meta.hash, signature)?; } meta::Kind::Variant { enum_hash, @@ -464,10 +521,15 @@ impl UnitBuilder { let rtti = Arc::new(VariantRtti { enum_hash, hash: meta.hash, - item: pool.item(meta.item_meta.item).to_owned(), + item: pool.item(meta.item_meta.item).try_to_owned()?, }); - if self.variant_rtti.insert(meta.hash, rtti).is_some() { + if self + .variant_rtti + .try_insert(meta.hash, rtti) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::VariantRttiConflict { hash: meta.hash }, @@ -480,11 +542,16 @@ impl UnitBuilder { }; let signature = DebugSignature::new( - pool.item(meta.item_meta.item).to_owned(), + pool.item(meta.item_meta.item).try_to_owned()?, DebugArgs::TupleArgs(args), ); - if self.functions.insert(meta.hash, info).is_some() { + if self + .functions + .try_insert(meta.hash, info) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::FunctionConflict { @@ -493,7 +560,9 @@ impl UnitBuilder { )); } - self.debug_info_mut().functions.insert(meta.hash, signature); + self.debug_mut()? + .functions + .try_insert(meta.hash, signature)?; } meta::Kind::Variant { enum_hash, @@ -505,10 +574,15 @@ impl UnitBuilder { let rtti = Arc::new(VariantRtti { enum_hash, hash, - item: pool.item(meta.item_meta.item).to_owned(), + item: pool.item(meta.item_meta.item).try_to_owned()?, }); - if self.variant_rtti.insert(hash, rtti).is_some() { + if self + .variant_rtti + .try_insert(hash, rtti) + .with_span(span)? + .is_some() + { return Err(compile::Error::new( span, ErrorKind::VariantRttiConflict { hash }, @@ -516,20 +590,31 @@ impl UnitBuilder { } } meta::Kind::Enum { .. } => { - self.constants.insert( - Hash::associated_function(meta.hash, Protocol::INTO_TYPE_NAME), - ConstValue::String(pool.item(meta.item_meta.item).to_string()), - ); + let name = pool + .item(meta.item_meta.item) + .try_to_string() + .with_span(span)?; + + self.constants + .try_insert( + Hash::associated_function(meta.hash, Protocol::INTO_TYPE_NAME), + ConstValue::String(name), + ) + .with_span(span)?; } meta::Kind::Const { .. } => { let Some(const_value) = query.get_const_value(meta.hash) else { return Err(compile::Error::msg( span, - format_args!("Missing constant for hash {}", meta.hash), + try_format!("Missing constant for hash {}", meta.hash), )); }; - self.constants.insert(meta.hash, const_value.clone()); + let value = const_value.try_clone().with_span(span)?; + + self.constants + .try_insert(meta.hash, value) + .with_span(span)?; } meta::Kind::Macro { .. } => (), meta::Kind::AttributeMacro { .. } => (), @@ -559,7 +644,7 @@ impl UnitBuilder { let hash = Hash::type_hash(item); let target = Hash::type_hash(target); - if self.reexports.insert(hash, target).is_some() { + if self.reexports.try_insert(hash, target)?.is_some() { return Err(compile::Error::new( location.span, ErrorKind::FunctionReExportConflict { hash }, @@ -586,12 +671,17 @@ impl UnitBuilder { let offset = unit_storage.offset(); let info = UnitFn::Offset { offset, call, args }; - let signature = DebugSignature::new(item.to_owned(), DebugArgs::Named(debug_args)); + let signature = DebugSignature::new(item.try_to_owned()?, DebugArgs::Named(debug_args)); if let Some((type_hash, name)) = instance { let instance_fn = Hash::associated_function(type_hash, name); - if self.functions.insert(instance_fn, info).is_some() { + if self + .functions + .try_insert(instance_fn, info) + .with_span(location.span)? + .is_some() + { return Err(compile::Error::new( location.span, ErrorKind::FunctionConflict { @@ -600,14 +690,19 @@ impl UnitBuilder { )); } - self.debug_info_mut() + self.debug_mut()? .functions - .insert(instance_fn, signature.clone()); + .try_insert(instance_fn, signature.try_clone()?)?; } let hash = Hash::type_hash(item); - if self.functions.insert(hash, info).is_some() { + if self + .functions + .try_insert(hash, info) + .with_span(location.span)? + .is_some() + { return Err(compile::Error::new( location.span, ErrorKind::FunctionConflict { @@ -616,13 +711,15 @@ impl UnitBuilder { )); } - self.constants.insert( - Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), - ConstValue::String(signature.path.to_string()), - ); + self.constants + .try_insert( + Hash::associated_function(hash, Protocol::INTO_TYPE_NAME), + ConstValue::String(signature.path.try_to_string().with_span(location.span)?), + ) + .with_span(location.span)?; - self.debug_info_mut().functions.insert(hash, signature); - self.functions_rev.insert(offset, hash); + self.debug_mut()?.functions.try_insert(hash, signature)?; + self.functions_rev.try_insert(offset, hash)?; self.add_assembly(location, assembly, unit_storage)?; Ok(()) } @@ -631,23 +728,33 @@ impl UnitBuilder { /// functions are provided. /// /// This can prevent a number of runtime errors, like missing functions. - pub(crate) fn link(&mut self, context: &Context, diagnostics: &mut Diagnostics) { + pub(crate) fn link( + &mut self, + context: &Context, + diagnostics: &mut Diagnostics, + ) -> alloc::Result<()> { for (hash, spans) in &self.required_functions { if self.functions.get(hash).is_none() && context.lookup_function(*hash).is_none() { diagnostics.error( SourceId::empty(), LinkerError::MissingFunction { hash: *hash, - spans: spans.clone(), + spans: spans.try_clone()?, }, ); } } + + Ok(()) } /// Insert and access debug information. - fn debug_info_mut(&mut self) -> &mut DebugInfo { - self.debug.get_or_insert_with(Default::default) + fn debug_mut(&mut self) -> alloc::Result<&mut DebugInfo> { + if self.debug.is_none() { + self.debug = Some(Box::try_new(DebugInfo::default())?); + } + + Ok(self.debug.as_mut().unwrap()) } /// Translate the given assembly into instructions. @@ -657,12 +764,11 @@ impl UnitBuilder { assembly: Assembly, storage: &mut dyn UnitEncoder, ) -> compile::Result<()> { - use core::fmt::Write; - self.label_count = assembly.label_count; - let base = storage.extend_offsets(assembly.labels.len()); - self.required_functions.extend(assembly.required_functions); + let base = storage.extend_offsets(assembly.labels.len())?; + self.required_functions + .try_extend(assembly.required_functions)?; for (offset, (_, labels)) in &assembly.labels { for label in labels { @@ -689,7 +795,7 @@ impl UnitBuilder { storage.mark_offset(index); } - labels.push(label.to_debug_label()); + labels.try_push(label.to_debug_label())?; } match inst { @@ -702,9 +808,7 @@ impl UnitBuilder { }) .with_span(span)?; - if let Err(fmt::Error) = write!(comment, "label:{}", label) { - return Err(compile::Error::msg(span, "Failed to write comment")); - } + write!(comment, "label:{}", label)?; storage.encode(Inst::Jump { jump }).with_span(span)?; } @@ -717,9 +821,7 @@ impl UnitBuilder { }) .with_span(span)?; - if let Err(fmt::Error) = write!(comment, "label:{}", label) { - return Err(compile::Error::msg(span, "Failed to write comment")); - } + write!(comment, "label:{}", label)?; storage.encode(Inst::JumpIf { jump }).with_span(span)?; } @@ -732,9 +834,7 @@ impl UnitBuilder { }) .with_span(span)?; - if let Err(fmt::Error) = write!(comment, "label:{}", label) { - return Err(compile::Error::msg(span, "Failed to write comment")); - } + write!(comment, "label:{}", label)?; storage.encode(Inst::JumpIfOrPop { jump }).with_span(span)?; } @@ -747,9 +847,7 @@ impl UnitBuilder { }) .with_span(span)?; - if let Err(fmt::Error) = write!(comment, "label:{}", label) { - return Err(compile::Error::msg(span, "Failed to write comment")); - } + write!(comment, "label:{}", label)?; storage .encode(Inst::JumpIfNotOrPop { jump }) @@ -764,9 +862,7 @@ impl UnitBuilder { }) .with_span(span)?; - if let Err(fmt::Error) = write!(comment, "label:{}", label) { - return Err(compile::Error::msg(span, "Failed to write comment")); - } + write!(comment, "label:{}", label)?; storage .encode(Inst::JumpIfBranch { branch, jump }) @@ -781,9 +877,7 @@ impl UnitBuilder { }) .with_span(span)?; - if let Err(fmt::Error) = write!(comment, "label:{}", label) { - return Err(compile::Error::msg(span, "Failed to write comment")); - } + write!(comment, "label:{}", label)?; storage .encode(Inst::PopAndJumpIfNot { count, jump }) @@ -798,9 +892,7 @@ impl UnitBuilder { }) .with_span(span)?; - if let Err(fmt::Error) = write!(comment, "label:{}", label) { - return Err(compile::Error::msg(span, "Failed to write comment")); - } + write!(comment, "label:{}", label)?; storage .encode(Inst::IterNext { offset, jump }) @@ -832,24 +924,22 @@ impl UnitBuilder { if let Some(c) = assembly.comments.get(&pos) { if !comment.is_empty() { - comment.push_str("; "); + comment.try_push_str("; ")?; } - comment.push_str(c); + comment.try_push_str(c)?; } - let debug = self.debug.get_or_insert_with(Default::default); - let comment = if comment.is_empty() { None } else { - Some(comment.into()) + Some(comment.try_into()?) }; - debug.instructions.insert( + self.debug_mut()?.instructions.try_insert( at, DebugInst::new(location.source_id, span, comment, labels), - ); + )?; } Ok(()) diff --git a/crates/rune/src/compile/v1/assemble.rs b/crates/rune/src/compile/v1/assemble.rs index f71e86a7c..165c42a65 100644 --- a/crates/rune/src/compile/v1/assemble.rs +++ b/crates/rune/src/compile/v1/assemble.rs @@ -1,7 +1,8 @@ use core::mem::{replace, take}; -use crate::no_std::prelude::*; - +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{try_format, Vec}; use crate::ast::{self, Span, Spanned}; use crate::compile::ir; use crate::compile::v1::{Layer, Loop, Loops, ScopeGuard, Scopes, Var}; @@ -19,7 +20,8 @@ use rune_macros::instrument; /// A needs hint for an expression. /// This is used to contextually determine what an expression is expected to /// produce. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) enum Needs { Value, None, @@ -53,16 +55,22 @@ pub(crate) struct Ctxt<'a, 'hir, 'arena> { impl<'a, 'hir, 'arena> Ctxt<'a, 'hir, 'arena> { /// Pop locals by simply popping them. - pub(crate) fn locals_pop(&mut self, total_var_count: usize, span: &dyn Spanned) { + pub(crate) fn locals_pop( + &mut self, + total_var_count: usize, + span: &dyn Spanned, + ) -> compile::Result<()> { match total_var_count { 0 => (), 1 => { - self.asm.push(Inst::Pop, span); + self.asm.push(Inst::Pop, span)?; } count => { - self.asm.push(Inst::PopN { count }, span); + self.asm.push(Inst::PopN { count }, span)?; } } + + Ok(()) } /// Clean up local variables by preserving the value that is on top and @@ -70,13 +78,19 @@ impl<'a, 'hir, 'arena> Ctxt<'a, 'hir, 'arena> { /// /// The clean operation will preserve the value that is on top of the stack, /// and pop the values under it. - pub(crate) fn locals_clean(&mut self, total_var_count: usize, span: &dyn Spanned) { + pub(crate) fn locals_clean( + &mut self, + total_var_count: usize, + span: &dyn Spanned, + ) -> compile::Result<()> { match total_var_count { 0 => (), count => { - self.asm.push(Inst::Clean { count }, span); + self.asm.push(Inst::Clean { count }, span)?; } } + + Ok(()) } /// Clean the last scope. @@ -89,9 +103,9 @@ impl<'a, 'hir, 'arena> Ctxt<'a, 'hir, 'arena> { let scope = self.scopes.pop(expected, span)?; if needs.value() { - self.locals_clean(scope.local, span); + self.locals_clean(scope.local, span)?; } else { - self.locals_pop(scope.local, span); + self.locals_pop(scope.local, span)?; } Ok(()) @@ -130,12 +144,12 @@ impl<'a, 'hir, 'arena> Ctxt<'a, 'hir, 'arena> { // TODO: precompile these and fetch using opaque id? for (hir, name) in args.iter().zip(&query_const_fn.ir_fn.args) { - compiled.push((ir::compiler::expr(hir, &mut compiler)?, name)); + compiled.try_push((ir::compiler::expr(hir, &mut compiler)?, name))?; } let mut interpreter = ir::Interpreter { budget: ir::Budget::new(1_000_000), - scopes: Default::default(), + scopes: ir::Scopes::new()?, module: from_module, item: from_item, q: self.q.borrow(), @@ -231,7 +245,7 @@ pub(crate) fn fn_from_item_fn<'hir>( } hir::FnArg::Pat(pat) => { let offset = cx.scopes.alloc(pat)?; - patterns.push((pat, offset)); + patterns.try_push((pat, offset))?; } } @@ -244,8 +258,8 @@ pub(crate) fn fn_from_item_fn<'hir>( if hir.body.statements.is_empty() { let total_var_count = cx.scopes.total(hir)?; - cx.locals_pop(total_var_count, hir); - cx.asm.push(Inst::ReturnUnit, hir); + cx.locals_pop(total_var_count, hir)?; + cx.asm.push(Inst::ReturnUnit, hir)?; return Ok(()); } @@ -255,8 +269,8 @@ pub(crate) fn fn_from_item_fn<'hir>( block(cx, &hir.body, Needs::None)?.apply(cx)?; let total_var_count = cx.scopes.total(hir)?; - cx.locals_pop(total_var_count, hir); - cx.asm.push(Inst::ReturnUnit, hir); + cx.locals_pop(total_var_count, hir)?; + cx.asm.push(Inst::ReturnUnit, hir)?; } cx.scopes.pop_last(hir)?; @@ -294,13 +308,13 @@ pub(crate) fn expr_closure_secondary<'hir>( } hir::FnArg::Pat(pat) => { let offset = cx.scopes.alloc(pat)?; - patterns.push((pat, offset)); + patterns.try_push((pat, offset))?; } } } if !hir.captures.is_empty() { - cx.asm.push(Inst::PushTuple, span); + cx.asm.push(Inst::PushTuple, span)?; for capture in hir.captures.iter().copied() { cx.scopes.define(capture, span)?; @@ -326,7 +340,7 @@ fn return_<'hir, T>( let clean = cx.scopes.total(span)?; let address = asm(cx, hir, Needs::Value)?.apply_targeted(cx)?; - cx.asm.push(Inst::Return { address, clean }, span); + cx.asm.push(Inst::Return { address, clean }, span)?; // Top address produces an anonymous variable, which is consumed by the // return statement. @@ -346,7 +360,7 @@ fn pat_with_offset<'hir>( ) -> compile::Result<()> { let load = |cx: &mut Ctxt<'_, 'hir, '_>, needs: Needs| { if needs.value() { - cx.asm.push(Inst::Copy { offset }, hir); + cx.asm.push(Inst::Copy { offset }, hir)?; } Ok(()) @@ -359,14 +373,14 @@ fn pat_with_offset<'hir>( .let_pattern_might_panic(cx.source_id, hir, cx.context()); let ok_label = cx.asm.new_label("let_ok"); - cx.asm.jump(&ok_label, hir); + cx.asm.jump(&ok_label, hir)?; cx.asm.label(&false_label)?; cx.asm.push( Inst::Panic { reason: PanicReason::UnmatchedPattern, }, hir, - ); + )?; cx.asm.label(&ok_label)?; } @@ -399,9 +413,9 @@ fn pat<'hir>( hir::PatKind::Path(kind) => match *kind { hir::PatPathKind::Kind(kind) => { load(cx, Needs::Value)?; - cx.asm.push(pat_sequence_kind_to_inst(*kind), hir); + cx.asm.push(pat_sequence_kind_to_inst(*kind), hir)?; cx.asm - .pop_and_jump_if_not(cx.scopes.local(hir)?, false_label, hir); + .pop_and_jump_if_not(cx.scopes.local(hir)?, false_label, hir)?; Ok(true) } hir::PatPathKind::Ident(name) => { @@ -435,9 +449,9 @@ fn pat_lit<'hir>( }; load(cx, Needs::Value)?; - cx.asm.push(inst, hir); + cx.asm.push(inst, hir)?; cx.asm - .pop_and_jump_if_not(cx.scopes.local(hir)?, false_label, hir); + .pop_and_jump_if_not(cx.scopes.local(hir)?, false_label, hir)?; Ok(true) } @@ -478,7 +492,7 @@ fn condition<'hir>( hir::Condition::Expr(e) => { let guard = cx.scopes.child(e)?; expr(cx, e, Needs::Value)?.apply(cx)?; - cx.asm.jump_if(then_label, e); + cx.asm.jump_if(then_label, e)?; Ok(cx.scopes.pop(guard, e)?) } hir::Condition::ExprLet(expr_let) => { @@ -494,10 +508,10 @@ fn condition<'hir>( }; if pat(cx, &expr_let.pat, &false_label, &load)? { - cx.asm.jump(then_label, span); + cx.asm.jump(then_label, span)?; cx.asm.label(&false_label)?; } else { - cx.asm.jump(then_label, span); + cx.asm.jump(then_label, span)?; }; Ok(cx.scopes.pop(expected, span)?) @@ -524,9 +538,9 @@ fn pat_sequence<'hir>( is_open: false } ) { - cx.asm.push(Inst::IsUnit, span); + cx.asm.push(Inst::IsUnit, span)?; cx.asm - .pop_and_jump_if_not(cx.scopes.local(span)?, false_label, span); + .pop_and_jump_if_not(cx.scopes.local(span)?, false_label, span)?; return Ok(()); } @@ -536,16 +550,16 @@ fn pat_sequence<'hir>( let inst = pat_sequence_kind_to_inst(hir.kind); - cx.asm.push(Inst::Copy { offset }, span); - cx.asm.push(inst, span); + cx.asm.push(Inst::Copy { offset }, span)?; + cx.asm.push(inst, span)?; cx.asm - .pop_and_jump_if_not(cx.scopes.local(span)?, false_label, span); + .pop_and_jump_if_not(cx.scopes.local(span)?, false_label, span)?; for (index, p) in hir.items.iter().enumerate() { let load = move |cx: &mut Ctxt<'_, 'hir, '_>, needs: Needs| { if needs.value() { - cx.asm.push(Inst::TupleIndexGetAt { offset, index }, p); + cx.asm.push(Inst::TupleIndexGetAt { offset, index }, p)?; } Ok(()) @@ -600,7 +614,7 @@ fn pat_object<'hir>( let mut string_slots = Vec::new(); for binding in hir.bindings { - string_slots.push(cx.q.unit.new_static_string(span, binding.key())?); + string_slots.try_push(cx.q.unit.new_static_string(span, binding.key())?)?; } let inst = match hir.kind { @@ -629,18 +643,19 @@ fn pat_object<'hir>( // Copy the temporary and check that its length matches the pattern and // that it is indeed a vector. - cx.asm.push(Inst::Copy { offset }, span); - cx.asm.push(inst, span); + cx.asm.push(Inst::Copy { offset }, span)?; + cx.asm.push(inst, span)?; cx.asm - .pop_and_jump_if_not(cx.scopes.local(span)?, false_label, span); + .pop_and_jump_if_not(cx.scopes.local(span)?, false_label, span)?; for (binding, slot) in hir.bindings.iter().zip(string_slots) { match *binding { hir::Binding::Binding(span, _, p) => { let load = move |cx: &mut Ctxt<'_, 'hir, '_>, needs: Needs| { if needs.value() { - cx.asm.push(Inst::ObjectIndexGetAt { offset, slot }, &span); + cx.asm + .push(Inst::ObjectIndexGetAt { offset, slot }, &span)?; } Ok(()) @@ -649,7 +664,8 @@ fn pat_object<'hir>( pat(cx, p, false_label, &load)?; } hir::Binding::Ident(span, name) => { - cx.asm.push(Inst::ObjectIndexGetAt { offset, slot }, &span); + cx.asm + .push(Inst::ObjectIndexGetAt { offset, slot }, &span)?; cx.scopes.define(hir::Name::Str(name), binding)?; } } @@ -665,7 +681,7 @@ fn block<'hir>( hir: &hir::Block<'hir>, needs: Needs, ) -> compile::Result> { - cx.contexts.push(hir.span()); + cx.contexts.try_push(hir.span())?; let scopes_count = cx.scopes.child(hir)?; let mut last = None::<(&hir::Expr<'_>, bool)>; @@ -708,13 +724,13 @@ fn block<'hir>( if needs.value() { if produced { - cx.locals_clean(scope.local, hir); + cx.locals_clean(scope.local, hir)?; } else { - cx.locals_pop(scope.local, hir); - cx.asm.push(Inst::unit(), hir); + cx.locals_pop(scope.local, hir)?; + cx.asm.push(Inst::unit(), hir)?; } } else { - cx.locals_pop(scope.local, hir); + cx.locals_pop(scope.local, hir)?; } cx.contexts @@ -744,10 +760,10 @@ fn builtin_format<'hir>( let spec = format::FormatSpec::new(flags, fill, align, width, precision, format_type); expr(cx, &format.value, Needs::Value)?.apply(cx)?; - cx.asm.push(Inst::Format { spec }, format); + cx.asm.push(Inst::Format { spec }, format)?; if !needs.value() { - cx.asm.push(Inst::Pop, format); + cx.asm.push(Inst::Pop, format)?; } Ok(Asm::top(format)) @@ -770,7 +786,7 @@ fn builtin_template<'hir>( if let hir::ExprKind::Lit(hir::Lit::Str(s)) = hir.kind { size_hint += s.len(); let slot = cx.q.unit.new_static_string(span, s)?; - cx.asm.push(Inst::String { slot }, span); + cx.asm.push(Inst::String { slot }, span)?; cx.scopes.alloc(span)?; continue; } @@ -792,10 +808,10 @@ fn builtin_template<'hir>( size_hint, }, span, - ); + )?; if !needs.value() { - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } let _ = cx.scopes.pop(expected, span)?; @@ -817,30 +833,30 @@ fn const_<'hir>( match value { ConstValue::EmptyTuple => { - cx.asm.push(Inst::unit(), span); + cx.asm.push(Inst::unit(), span)?; } ConstValue::Byte(b) => { - cx.asm.push(Inst::byte(*b), span); + cx.asm.push(Inst::byte(*b), span)?; } ConstValue::Char(ch) => { - cx.asm.push(Inst::char(*ch), span); + cx.asm.push(Inst::char(*ch), span)?; } ConstValue::Integer(n) => { - cx.asm.push(Inst::integer(*n), span); + cx.asm.push(Inst::integer(*n), span)?; } ConstValue::Float(n) => { - cx.asm.push(Inst::float(*n), span); + cx.asm.push(Inst::float(*n), span)?; } ConstValue::Bool(b) => { - cx.asm.push(Inst::bool(*b), span); + cx.asm.push(Inst::bool(*b), span)?; } ConstValue::String(s) => { let slot = cx.q.unit.new_static_string(span, s)?; - cx.asm.push(Inst::String { slot }, span); + cx.asm.push(Inst::String { slot }, span)?; } ConstValue::Bytes(b) => { let slot = cx.q.unit.new_static_bytes(span, b)?; - cx.asm.push(Inst::Bytes { slot }, span); + cx.asm.push(Inst::Bytes { slot }, span)?; } ConstValue::Option(option) => match option { Some(value) => { @@ -850,7 +866,7 @@ fn const_<'hir>( variant: InstVariant::Some, }, span, - ); + )?; } None => { cx.asm.push( @@ -858,7 +874,7 @@ fn const_<'hir>( variant: InstVariant::None, }, span, - ); + )?; } }, ConstValue::Vec(vec) => { @@ -866,17 +882,17 @@ fn const_<'hir>( const_(cx, value, span, Needs::Value)?; } - cx.asm.push(Inst::Vec { count: vec.len() }, span); + cx.asm.push(Inst::Vec { count: vec.len() }, span)?; } ConstValue::Tuple(tuple) => { for value in tuple.iter() { const_(cx, value, span, Needs::Value)?; } - cx.asm.push(Inst::Tuple { count: tuple.len() }, span); + cx.asm.push(Inst::Tuple { count: tuple.len() }, span)?; } ConstValue::Object(object) => { - let mut entries = object.iter().collect::>(); + let mut entries = object.iter().try_collect::>()?; entries.sort_by_key(|k| k.0); for (_, value) in entries.iter().copied() { @@ -887,7 +903,7 @@ fn const_<'hir>( cx.q.unit .new_static_object_keys_iter(span, entries.iter().map(|e| e.0))?; - cx.asm.push(Inst::Object { slot }, span); + cx.asm.push(Inst::Object { slot }, span)?; } } @@ -914,11 +930,11 @@ fn expr<'hir>( value: InstValue::Type(ty), }, span, - ); + )?; Asm::top(span) } hir::ExprKind::Fn(hash) => { - cx.asm.push(Inst::LoadFn { hash }, span); + cx.asm.push(Inst::LoadFn { hash }, span)?; Asm::top(span) } hir::ExprKind::For(hir) => expr_for(cx, hir, span, needs)?, @@ -995,7 +1011,7 @@ fn expr_assign<'hir>( expr(cx, &field_access.expr, Needs::Value)?.apply(cx)?; cx.scopes.alloc(span)?; - cx.asm.push(Inst::ObjectIndexSet { slot }, span); + cx.asm.push(Inst::ObjectIndexSet { slot }, span)?; cx.scopes.free(span, 2)?; true } @@ -1004,7 +1020,7 @@ fn expr_assign<'hir>( cx.scopes.alloc(&hir.rhs)?; expr(cx, &field_access.expr, Needs::Value)?.apply(cx)?; - cx.asm.push(Inst::TupleIndexSet { index }, span); + cx.asm.push(Inst::TupleIndexSet { index }, span)?; cx.scopes.free(span, 1)?; true } @@ -1023,7 +1039,7 @@ fn expr_assign<'hir>( expr(cx, &expr_index_get.index, Needs::Value)?.apply(cx)?; cx.scopes.alloc(span)?; - cx.asm.push(Inst::IndexSet, span); + cx.asm.push(Inst::IndexSet, span)?; cx.scopes.free(span, 3)?; true } @@ -1035,7 +1051,7 @@ fn expr_assign<'hir>( } if needs.value() { - cx.asm.push(Inst::unit(), span); + cx.asm.push(Inst::unit(), span)?; } Ok(Asm::top(span)) @@ -1050,10 +1066,10 @@ fn expr_await<'hir>( needs: Needs, ) -> compile::Result> { expr(cx, hir, Needs::Value)?.apply(cx)?; - cx.asm.push(Inst::Await, span); + cx.asm.push(Inst::Await, span)?; if !needs.value() { - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } Ok(Asm::top(span)) @@ -1116,12 +1132,12 @@ fn expr_binary<'hir>( } }; - cx.asm.push(Inst::Op { op, a, b }, span); + cx.asm.push(Inst::Op { op, a, b }, span)?; // NB: we put it here to preserve the call in case it has side effects. // But if we don't need the value, then pop it from the stack. if !needs.value() { - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } cx.scopes.pop(guard, span)?; @@ -1141,10 +1157,10 @@ fn expr_binary<'hir>( match bin_op { ast::BinOp::And(..) => { - cx.asm.jump_if_not_or_pop(&end_label, lhs); + cx.asm.jump_if_not_or_pop(&end_label, lhs)?; } ast::BinOp::Or(..) => { - cx.asm.jump_if_or_pop(&end_label, lhs); + cx.asm.jump_if_or_pop(&end_label, lhs)?; } op => { return Err(compile::Error::new( @@ -1159,7 +1175,7 @@ fn expr_binary<'hir>( cx.asm.label(&end_label)?; if !needs.value() { - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } Ok(()) @@ -1220,10 +1236,10 @@ fn expr_binary<'hir>( } }; - cx.asm.push(Inst::Assign { target, op }, span); + cx.asm.push(Inst::Assign { target, op }, span)?; if needs.value() { - cx.asm.push(Inst::unit(), span); + cx.asm.push(Inst::unit(), span)?; } Ok(()) @@ -1273,13 +1289,14 @@ fn const_item<'hir>( span: &dyn Spanned, needs: Needs, ) -> compile::Result> { - let Some(const_value) = cx.q.get_const_value(hash).cloned() else { + let Some(const_value) = cx.q.get_const_value(hash) else { return Err(compile::Error::msg( span, - format_args!("Missing constant value for hash {hash}"), + try_format!("Missing constant value for hash {hash}"), )); }; + let const_value = const_value.try_clone().with_span(span)?; const_(cx, &const_value, span, needs)?; Ok(Asm::top(span)) } @@ -1294,34 +1311,34 @@ fn expr_break<'hir>( span: &dyn Spanned, _: Needs, ) -> compile::Result> { - let Some(current_loop) = cx.loops.last().cloned() else { + let Some(current_loop) = cx.loops.last().try_cloned()? else { return Err(compile::Error::new(span, ErrorKind::BreakOutsideOfLoop)); }; let (last_loop, to_drop, has_value) = match (hir.label, hir.expr) { (None, Some(e)) => { expr(cx, e, current_loop.needs)?.apply(cx)?; - let to_drop = current_loop.drop.into_iter().collect(); + let to_drop = current_loop.drop.into_iter().try_collect()?; (current_loop, to_drop, true) } (Some(label), None) => { let (last_loop, to_drop) = cx.loops.walk_until_label(label, span)?; - (last_loop.clone(), to_drop, false) + (last_loop.try_clone()?, to_drop, false) } (Some(label), Some(e)) => { expr(cx, e, current_loop.needs)?.apply(cx)?; let (last_loop, to_drop) = cx.loops.walk_until_label(label, span)?; - (last_loop.clone(), to_drop, true) + (last_loop.try_clone()?, to_drop, true) } (None, None) => { - let to_drop = current_loop.drop.into_iter().collect(); + let to_drop = current_loop.drop.into_iter().try_collect()?; (current_loop, to_drop, false) } }; // Drop loop temporaries. Typically an iterator. for offset in to_drop { - cx.asm.push(Inst::Drop { offset }, span); + cx.asm.push(Inst::Drop { offset }, span)?; } let vars = cx @@ -1333,16 +1350,16 @@ fn expr_break<'hir>( if last_loop.needs.value() { if has_value { - cx.locals_clean(vars, span); + cx.locals_clean(vars, span)?; } else { - cx.locals_pop(vars, span); - cx.asm.push(Inst::unit(), span); + cx.locals_pop(vars, span)?; + cx.asm.push(Inst::unit(), span)?; } } else { - cx.locals_pop(vars, span); + cx.locals_pop(vars, span)?; } - cx.asm.jump(&last_loop.break_label, span); + cx.asm.jump(&last_loop.break_label, span)?; Ok(Asm::top(span)) } @@ -1368,7 +1385,7 @@ fn expr_call<'hir>( var.copy(cx, span, &"call")?; cx.scopes.alloc(span)?; - cx.asm.push(Inst::CallFn { args }, span); + cx.asm.push(Inst::CallFn { args }, span)?; cx.scopes.free(span, hir.args.len() + 1)?; } @@ -1381,7 +1398,7 @@ fn expr_call<'hir>( cx.scopes.alloc(span)?; } - cx.asm.push(Inst::CallAssociated { hash, args }, span); + cx.asm.push(Inst::CallAssociated { hash, args }, span)?; cx.scopes.free(span, hir.args.len() + 1)?; } hir::Call::Meta { hash } => { @@ -1390,7 +1407,7 @@ fn expr_call<'hir>( cx.scopes.alloc(span)?; } - cx.asm.push(Inst::Call { hash, args }, span); + cx.asm.push(Inst::Call { hash, args }, span)?; cx.scopes.free(span, args)?; } hir::Call::Expr { expr: e } => { @@ -1402,7 +1419,7 @@ fn expr_call<'hir>( expr(cx, e, Needs::Value)?.apply(cx)?; cx.scopes.alloc(span)?; - cx.asm.push(Inst::CallFn { args }, span); + cx.asm.push(Inst::CallFn { args }, span)?; cx.scopes.free(span, args + 1)?; } @@ -1418,7 +1435,7 @@ fn expr_call<'hir>( } if !needs.value() { - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } Ok(Asm::top(span)) @@ -1456,7 +1473,7 @@ fn expr_call_closure<'hir>( count: hir.captures.len(), }, span, - ); + )?; Ok(Asm::top(span)) } @@ -1469,13 +1486,13 @@ fn expr_continue<'hir>( span: &dyn Spanned, _: Needs, ) -> compile::Result> { - let Some(current_loop) = cx.loops.last().cloned() else { + let Some(current_loop) = cx.loops.last().try_cloned()? else { return Err(compile::Error::new(span, ErrorKind::ContinueOutsideOfLoop)); }; let last_loop = if let Some(label) = hir.label { let (last_loop, _) = cx.loops.walk_until_label(label, span)?; - last_loop.clone() + last_loop.try_clone()? } else { current_loop }; @@ -1487,9 +1504,9 @@ fn expr_continue<'hir>( .ok_or("Var count should be larger") .with_span(span)?; - cx.locals_pop(vars, span); + cx.locals_pop(vars, span)?; - cx.asm.jump(&last_loop.continue_label, span); + cx.asm.jump(&last_loop.continue_label, span)?; Ok(Asm::top(span)) } @@ -1522,7 +1539,7 @@ fn expr_field_access<'hir>( if !needs.value() { cx.q.diagnostics.not_used(cx.source_id, span, cx.context()); - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } return Ok(Asm::top(span)); @@ -1532,11 +1549,11 @@ fn expr_field_access<'hir>( match hir.expr_field { hir::ExprField::Index(index) => { - cx.asm.push(Inst::TupleIndexGet { index }, span); + cx.asm.push(Inst::TupleIndexGet { index }, span)?; if !needs.value() { cx.q.diagnostics.not_used(cx.source_id, span, cx.context()); - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } Ok(Asm::top(span)) @@ -1544,11 +1561,11 @@ fn expr_field_access<'hir>( hir::ExprField::Ident(field) => { let slot = cx.q.unit.new_static_string(span, field)?; - cx.asm.push(Inst::ObjectIndexGet { slot }, span); + cx.asm.push(Inst::ObjectIndexGet { slot }, span)?; if !needs.value() { cx.q.diagnostics.not_used(cx.source_id, span, cx.context()); - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } Ok(Asm::top(span)) @@ -1591,7 +1608,7 @@ fn expr_for<'hir>( // Declare named loop variable. let binding_offset = { - cx.asm.push(Inst::unit(), &hir.iter); + cx.asm.push(Inst::unit(), &hir.iter)?; cx.scopes.alloc(&hir.binding)? }; @@ -1626,13 +1643,13 @@ fn expr_for<'hir>( cx.loops.push(Loop { label: hir.label, - continue_label: continue_label.clone(), + continue_label: continue_label.try_clone()?, continue_var_count, - break_label: break_label.clone(), + break_label: break_label.try_clone()?, break_var_count, needs, drop: Some(iter_offset), - }); + })?; // Use the memoized loop variable. if let Some(next_offset) = next_offset { @@ -1652,14 +1669,14 @@ fn expr_for<'hir>( &"copy next", )?; - cx.asm.push(Inst::CallFn { args: 1 }, span); + cx.asm.push(Inst::CallFn { args: 1 }, span)?; cx.asm.push( Inst::Replace { offset: binding_offset, }, &hir.binding, - ); + )?; } else { // call the `next` function to get the next level of iteration, bind the // result to the loop variable in the loop. @@ -1668,7 +1685,7 @@ fn expr_for<'hir>( offset: iter_offset, }, &hir.iter, - ); + )?; cx.asm.push_with_comment( Inst::CallAssociated { @@ -1684,11 +1701,11 @@ fn expr_for<'hir>( offset: binding_offset, }, &hir.binding, - ); + )?; } // Test loop condition and unwrap the option, or jump to `end_label` if the current value is `None`. - cx.asm.iter_next(binding_offset, &end_label, &hir.binding); + cx.asm.iter_next(binding_offset, &end_label, &hir.binding)?; let guard = cx.scopes.child(&hir.body)?; @@ -1697,7 +1714,7 @@ fn expr_for<'hir>( block(cx, &hir.body, Needs::None)?.apply(cx)?; cx.clean_last_scope(span, guard, Needs::None)?; - cx.asm.jump(&continue_label, span); + cx.asm.jump(&continue_label, span)?; cx.asm.label(&end_label)?; // Drop the iterator. @@ -1706,13 +1723,13 @@ fn expr_for<'hir>( offset: iter_offset, }, span, - ); + )?; cx.clean_last_scope(span, loop_scope_expected, Needs::None)?; // NB: If a value is needed from a for loop, encode it as a unit. if needs.value() { - cx.asm.push(Inst::unit(), span); + cx.asm.push(Inst::unit(), span)?; } // NB: breaks produce their own value. @@ -1746,7 +1763,7 @@ fn expr_if<'hir>( let label = cx.asm.new_label("if_branch"); let scope = condition(cx, cond, &label)?; - branches.push((branch, label, scope)); + branches.try_push((branch, label, scope))?; } // use fallback as fall through. @@ -1756,23 +1773,23 @@ fn expr_if<'hir>( // NB: if we must produce a value and there is no fallback branch, // encode the result of the statement as a unit. if needs.value() { - cx.asm.push(Inst::unit(), span); + cx.asm.push(Inst::unit(), span)?; } } - cx.asm.jump(&end_label, span); + cx.asm.jump(&end_label, span)?; let mut it = branches.into_iter().peekable(); while let Some((branch, label, scope)) = it.next() { cx.asm.label(&label)?; - let scopes = cx.scopes.push(scope); + let scopes = cx.scopes.push(scope)?; block(cx, &branch.block, needs)?.apply(cx)?; cx.clean_last_scope(branch, scopes, needs)?; if it.peek().is_some() { - cx.asm.jump(&end_label, branch); + cx.asm.jump(&end_label, branch)?; } } @@ -1793,12 +1810,12 @@ fn expr_index<'hir>( let target = expr(cx, &hir.target, Needs::Value)?.apply_targeted(cx)?; let index = expr(cx, &hir.index, Needs::Value)?.apply_targeted(cx)?; - cx.asm.push(Inst::IndexGet { index, target }, span); + cx.asm.push(Inst::IndexGet { index, target }, span)?; // NB: we still need to perform the operation since it might have side // effects, but pop the result in case a value is not needed. if !needs.value() { - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } cx.scopes.pop(guard, span)?; @@ -1825,21 +1842,21 @@ fn expr_let<'hir>( .let_pattern_might_panic(cx.source_id, hir, cx.context()); let ok_label = cx.asm.new_label("let_ok"); - cx.asm.jump(&ok_label, hir); + cx.asm.jump(&ok_label, hir)?; cx.asm.label(&false_label)?; cx.asm.push( Inst::Panic { reason: PanicReason::UnmatchedPattern, }, hir, - ); + )?; cx.asm.label(&ok_label)?; } // If a value is needed for a let expression, it is evaluated as a unit. if needs.value() { - cx.asm.push(Inst::unit(), hir); + cx.asm.push(Inst::unit(), hir)?; } Ok(Asm::top(hir)) @@ -1871,7 +1888,7 @@ fn expr_match<'hir>( let load = move |this: &mut Ctxt, needs: Needs| { if needs.value() { - this.asm.push(Inst::Copy { offset }, span); + this.asm.push(Inst::Copy { offset }, span)?; } Ok(()) @@ -1888,27 +1905,28 @@ fn expr_match<'hir>( cx.clean_last_scope(span, guard, Needs::Value)?; let scope = cx.scopes.pop(parent_guard, span)?; - cx.asm.pop_and_jump_if_not(scope.local, &match_false, span); + cx.asm + .pop_and_jump_if_not(scope.local, &match_false, span)?; - cx.asm.jump(&branch_label, span); + cx.asm.jump(&branch_label, span)?; scope } else { cx.scopes.pop(parent_guard, span)? }; - cx.asm.jump(&branch_label, span); + cx.asm.jump(&branch_label, span)?; cx.asm.label(&match_false)?; - branches.push((branch_label, scope)); + branches.try_push((branch_label, scope))?; } // what to do in case nothing matches and the pattern doesn't have any // default match branch. if needs.value() { - cx.asm.push(Inst::unit(), span); + cx.asm.push(Inst::unit(), span)?; } - cx.asm.jump(&end_label, span); + cx.asm.jump(&end_label, span)?; let mut it = hir.branches.iter().zip(&branches).peekable(); @@ -1917,12 +1935,12 @@ fn expr_match<'hir>( cx.asm.label(label)?; - let expected = cx.scopes.push(scope.clone()); + let expected = cx.scopes.push(scope.try_clone()?)?; expr(cx, &branch.body, needs)?.apply(cx)?; cx.clean_last_scope(span, expected, needs)?; if it.peek().is_some() { - cx.asm.jump(&end_label, span); + cx.asm.jump(&end_label, span)?; } } @@ -1956,27 +1974,27 @@ fn expr_object<'hir>( match hir.kind { hir::ExprObjectKind::EmptyStruct { hash } => { - cx.asm.push(Inst::EmptyStruct { hash }, span); + cx.asm.push(Inst::EmptyStruct { hash }, span)?; } hir::ExprObjectKind::Struct { hash } => { - cx.asm.push(Inst::Struct { hash, slot }, span); + cx.asm.push(Inst::Struct { hash, slot }, span)?; } hir::ExprObjectKind::StructVariant { hash } => { - cx.asm.push(Inst::StructVariant { hash, slot }, span); + cx.asm.push(Inst::StructVariant { hash, slot }, span)?; } hir::ExprObjectKind::ExternalType { hash, args } => { reorder_field_assignments(cx, hir, base, span)?; - cx.asm.push(Inst::Call { hash, args }, span); + cx.asm.push(Inst::Call { hash, args }, span)?; } hir::ExprObjectKind::Anonymous => { - cx.asm.push(Inst::Object { slot }, span); + cx.asm.push(Inst::Object { slot }, span)?; } } // No need to encode an object since the value is not needed. if !needs.value() { cx.q.diagnostics.not_used(cx.source_id, span, cx.context()); - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } cx.scopes.pop(guard, span)?; @@ -1991,17 +2009,17 @@ fn reorder_field_assignments<'hir>( base: usize, span: &dyn Spanned, ) -> compile::Result<()> { - let mut order = Vec::with_capacity(hir.assignments.len()); + let mut order = Vec::try_with_capacity(hir.assignments.len())?; for assign in hir.assignments { let Some(position) = assign.position else { return Err(compile::Error::msg( span, - format_args!("Missing position for field assignment {}", assign.key.1), + try_format!("Missing position for field assignment {}", assign.key.1), )); }; - order.push(position); + order.try_push(position)?; } for a in 0..hir.assignments.len() { @@ -2023,7 +2041,7 @@ fn reorder_field_assignments<'hir>( )); }; - cx.asm.push(Inst::Swap { a, b }, span); + cx.asm.push(Inst::Swap { a, b }, span)?; } } @@ -2074,7 +2092,7 @@ fn expr_range<'hir>( }; if needs.value() { - cx.asm.push(Inst::Range { range }, span); + cx.asm.push(Inst::Range { range }, span)?; } cx.scopes.free(span, count)?; @@ -2093,7 +2111,7 @@ fn expr_return<'hir>( // NB: drop any loop temporaries. for l in cx.loops.iter() { if let Some(offset) = l.drop { - cx.asm.push(Inst::Drop { offset }, span); + cx.asm.push(Inst::Drop { offset }, span)?; } } @@ -2103,8 +2121,8 @@ fn expr_return<'hir>( // NB: we actually want total_var_count here since we need to clean up // _every_ variable declared until we reached the current return. let clean = cx.scopes.total(span)?; - cx.locals_pop(clean, span); - cx.asm.push(Inst::ReturnUnit, span); + cx.locals_pop(clean, span)?; + cx.asm.push(Inst::ReturnUnit, span)?; } Ok(Asm::top(span)) @@ -2118,7 +2136,7 @@ fn expr_select<'hir>( span: &dyn Spanned, needs: Needs, ) -> compile::Result> { - cx.contexts.push(span.span()); + cx.contexts.try_push(span.span())?; let len = hir.branches.len(); let mut default_branch = None; @@ -2130,7 +2148,7 @@ fn expr_select<'hir>( match *branch { hir::ExprSelectBranch::Pat(pat) => { let label = cx.asm.new_label("select_branch"); - branches.push((label, pat)); + branches.try_push((label, pat))?; } hir::ExprSelectBranch::Default(def) => { if default_branch.is_some() { @@ -2147,22 +2165,22 @@ fn expr_select<'hir>( expr(cx, &branch.expr, Needs::Value)?.apply(cx)?; } - cx.asm.push(Inst::Select { len }, span); + cx.asm.push(Inst::Select { len }, span)?; for (branch, (label, _)) in branches.iter().enumerate() { - cx.asm.jump_if_branch(branch as i64, label, span); + cx.asm.jump_if_branch(branch as i64, label, span)?; } if let Some((_, label)) = &default_branch { - cx.asm.push(Inst::Pop, span); - cx.asm.jump(label, span); + cx.asm.push(Inst::Pop, span)?; + cx.asm.jump(label, span)?; } if !needs.value() { - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } - cx.asm.jump(&end_label, span); + cx.asm.jump(&end_label, span)?; for (label, branch) in branches { cx.asm.label(&label)?; @@ -2174,7 +2192,7 @@ fn expr_select<'hir>( cx.scopes.define(hir::Name::Str(name), &branch.pat)?; } hir::PatKind::Ignore => { - cx.asm.push(Inst::Pop, &branch.body); + cx.asm.push(Inst::Pop, &branch.body)?; } _ => { return Err(compile::Error::new( @@ -2187,7 +2205,7 @@ fn expr_select<'hir>( // Set up a new scope with the binding. expr(cx, &branch.body, needs)?.apply(cx)?; cx.clean_last_scope(&branch.body, expected, needs)?; - cx.asm.jump(&end_label, span); + cx.asm.jump(&end_label, span)?; } if let Some((branch, label)) = default_branch { @@ -2223,7 +2241,7 @@ fn expr_try<'hir>( preserve: needs.value(), }, span, - ); + )?; if let InstAddress::Top = address { cx.scopes.free(span, 1)?; @@ -2263,14 +2281,14 @@ fn expr_tuple<'hir>( args: [$($var,)*], }, span, - ); + )?; cx.scopes.pop(guard, span)?; }}; } if hir.items.is_empty() { - cx.asm.push(Inst::unit(), span); + cx.asm.push(Inst::unit(), span)?; } else { match hir.items.len() { 1 => tuple!(Tuple1, e1), @@ -2288,7 +2306,7 @@ fn expr_tuple<'hir>( count: hir.items.len(), }, span, - ); + )?; cx.scopes.free(span, hir.items.len())?; } @@ -2297,7 +2315,7 @@ fn expr_tuple<'hir>( if !needs.value() { cx.q.diagnostics.not_used(cx.source_id, span, cx.context()); - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } Ok(Asm::top(span)) @@ -2315,10 +2333,10 @@ fn expr_unary<'hir>( match hir.op { ast::UnOp::Not(..) => { - cx.asm.push(Inst::Not, span); + cx.asm.push(Inst::Not, span)?; } ast::UnOp::Neg(..) => { - cx.asm.push(Inst::Neg, span); + cx.asm.push(Inst::Neg, span)?; } op => { return Err(compile::Error::new( @@ -2331,7 +2349,7 @@ fn expr_unary<'hir>( // NB: we put it here to preserve the call in case it has side effects. // But if we don't need the value, then pop it from the stack. if !needs.value() { - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } Ok(Asm::top(span)) @@ -2352,14 +2370,14 @@ fn expr_vec<'hir>( cx.scopes.alloc(e)?; } - cx.asm.push(Inst::Vec { count }, span); + cx.asm.push(Inst::Vec { count }, span)?; cx.scopes.free(span, hir.items.len())?; // Evaluate the expressions one by one, then pop them to cause any // side effects (without creating an object). if !needs.value() { cx.q.diagnostics.not_used(cx.source_id, span, cx.context()); - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } Ok(Asm::top(span)) @@ -2382,21 +2400,21 @@ fn expr_loop<'hir>( cx.loops.push(Loop { label: hir.label, - continue_label: continue_label.clone(), + continue_label: continue_label.try_clone()?, continue_var_count: var_count, - break_label: break_label.clone(), + break_label: break_label.try_clone()?, break_var_count: var_count, needs, drop: None, - }); + })?; cx.asm.label(&continue_label)?; let expected = if let Some(hir) = hir.condition { let then_scope = condition(cx, hir, &then_label)?; - let expected = cx.scopes.push(then_scope); + let expected = cx.scopes.push(then_scope)?; - cx.asm.jump(&end_label, span); + cx.asm.jump(&end_label, span)?; cx.asm.label(&then_label)?; Some(expected) } else { @@ -2409,11 +2427,11 @@ fn expr_loop<'hir>( cx.clean_last_scope(span, expected, Needs::None)?; } - cx.asm.jump(&continue_label, span); + cx.asm.jump(&continue_label, span)?; cx.asm.label(&end_label)?; if needs.value() { - cx.asm.push(Inst::unit(), span); + cx.asm.push(Inst::unit(), span)?; } // NB: breaks produce their own value / perform their own cleanup. @@ -2432,13 +2450,13 @@ fn expr_yield<'hir>( ) -> compile::Result> { if let Some(e) = hir { expr(cx, e, Needs::Value)?.apply(cx)?; - cx.asm.push(Inst::Yield, span); + cx.asm.push(Inst::Yield, span)?; } else { - cx.asm.push(Inst::YieldUnit, span); + cx.asm.push(Inst::YieldUnit, span)?; } if !needs.value() { - cx.asm.push(Inst::Pop, span); + cx.asm.push(Inst::Pop, span)?; } Ok(Asm::top(span)) @@ -2460,27 +2478,27 @@ fn lit<'hir>( match hir { hir::Lit::Bool(boolean) => { - cx.asm.push(Inst::bool(boolean), span); + cx.asm.push(Inst::bool(boolean), span)?; } hir::Lit::Byte(byte) => { - cx.asm.push(Inst::byte(byte), span); + cx.asm.push(Inst::byte(byte), span)?; } hir::Lit::Char(char) => { - cx.asm.push(Inst::char(char), span); + cx.asm.push(Inst::char(char), span)?; } hir::Lit::Integer(integer) => { - cx.asm.push(Inst::integer(integer), span); + cx.asm.push(Inst::integer(integer), span)?; } hir::Lit::Float(float) => { - cx.asm.push(Inst::float(float), span); + cx.asm.push(Inst::float(float), span)?; } hir::Lit::Str(string) => { let slot = cx.q.unit.new_static_string(span, string)?; - cx.asm.push(Inst::String { slot }, span); + cx.asm.push(Inst::String { slot }, span)?; } hir::Lit::ByteStr(bytes) => { let slot = cx.q.unit.new_static_bytes(span, bytes)?; - cx.asm.push(Inst::Bytes { slot }, span); + cx.asm.push(Inst::Bytes { slot }, span)?; } }; @@ -2507,21 +2525,21 @@ fn local<'hir>( .let_pattern_might_panic(cx.source_id, hir, cx.context()); let ok_label = cx.asm.new_label("let_ok"); - cx.asm.jump(&ok_label, hir); + cx.asm.jump(&ok_label, hir)?; cx.asm.label(&false_label)?; cx.asm.push( Inst::Panic { reason: PanicReason::UnmatchedPattern, }, hir, - ); + )?; cx.asm.label(&ok_label)?; } // If a value is needed for a let expression, it is evaluated as a unit. if needs.value() { - cx.asm.push(Inst::unit(), hir); + cx.asm.push(Inst::unit(), hir)?; } Ok(Asm::top(hir)) diff --git a/crates/rune/src/compile/v1/loops.rs b/crates/rune/src/compile/v1/loops.rs index 6b4b521b0..a40afaecc 100644 --- a/crates/rune/src/compile/v1/loops.rs +++ b/crates/rune/src/compile/v1/loops.rs @@ -1,12 +1,13 @@ -use crate::no_std::prelude::*; - +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, Vec}; use crate::ast::Spanned; use crate::compile::v1::Needs; use crate::compile::{self, ErrorKind}; use crate::runtime::Label; /// Loops we are inside. -#[derive(Clone)] +#[derive(TryClone)] pub(crate) struct Loop<'hir> { /// The optional label of the start of the loop. pub(crate) label: Option<&'hir str>, @@ -31,7 +32,7 @@ pub(crate) struct Loops<'hir> { impl<'hir> Loops<'hir> { /// Construct a new collection of loops. pub(crate) fn new() -> Self { - Self { loops: vec![] } + Self { loops: Vec::new() } } /// Get the last loop context. @@ -40,8 +41,9 @@ impl<'hir> Loops<'hir> { } /// Push loop information. - pub(crate) fn push(&mut self, l: Loop<'hir>) { - self.loops.push(l); + pub(crate) fn push(&mut self, l: Loop<'hir>) -> alloc::Result<()> { + self.loops.try_push(l)?; + Ok(()) } pub(crate) fn pop(&mut self) { @@ -58,7 +60,7 @@ impl<'hir> Loops<'hir> { let mut to_drop = Vec::new(); for l in self.loops.iter().rev() { - to_drop.extend(l.drop); + to_drop.try_extend(l.drop)?; let Some(label) = l.label else { continue; @@ -72,7 +74,7 @@ impl<'hir> Loops<'hir> { Err(compile::Error::new( span, ErrorKind::MissingLoopLabel { - label: expected.into(), + label: expected.try_into()?, }, )) } diff --git a/crates/rune/src/compile/v1/scopes.rs b/crates/rune/src/compile/v1/scopes.rs index ac3a6cc8e..017f7bdf5 100644 --- a/crates/rune/src/compile/v1/scopes.rs +++ b/crates/rune/src/compile/v1/scopes.rs @@ -1,8 +1,8 @@ use core::fmt; -use crate::no_std::collections::HashMap; -use crate::no_std::prelude::*; - +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, try_format, try_vec, HashMap, Vec}; use crate::ast::Spanned; use crate::compile::v1::Ctxt; use crate::compile::{self, Assembly, ErrorKind, WithSpan}; @@ -13,7 +13,8 @@ use crate::SourceId; /// A locally declared variable, its calculated stack offset and where it was /// declared in its source file. -#[derive(Clone, Copy)] +#[derive(TryClone, Clone, Copy)] +#[try_clone(copy)] pub struct Var<'hir> { /// Offset from the current stack frame. pub(crate) offset: usize, @@ -77,7 +78,7 @@ impl<'hir> Var<'hir> { } } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct Layer<'hir> { /// Named variables. variables: HashMap, Var<'hir>>, @@ -121,11 +122,11 @@ pub(crate) struct Scopes<'hir> { impl<'hir> Scopes<'hir> { /// Construct a new collection of scopes. - pub(crate) fn new(source_id: SourceId) -> Self { - Self { - layers: vec![Layer::new()], + pub(crate) fn new(source_id: SourceId) -> alloc::Result { + Ok(Self { + layers: try_vec![Layer::new()], source_id, - } + }) } /// Get the local with the given name. @@ -141,7 +142,9 @@ impl<'hir> Scopes<'hir> { for layer in self.layers.iter().rev() { if let Some(var) = layer.variables.get(&name) { tracing::trace!(?var, "getting var"); - q.visitor.visit_variable_use(self.source_id, var.span, span); + q.visitor + .visit_variable_use(self.source_id, var.span, span) + .with_span(span)?; if let Some(_moved_at) = var.moved_at { return Err(compile::Error::new( @@ -159,7 +162,7 @@ impl<'hir> Scopes<'hir> { Err(compile::Error::msg( span, - format_args!("Missing variable `{name}`"), + try_format!("Missing variable `{name}`"), )) } @@ -176,7 +179,9 @@ impl<'hir> Scopes<'hir> { for layer in self.layers.iter_mut().rev() { if let Some(var) = layer.variables.get_mut(&name) { tracing::trace!(?var, "taking var"); - q.visitor.visit_variable_use(self.source_id, var.span, span); + q.visitor + .visit_variable_use(self.source_id, var.span, span) + .with_span(span)?; if let Some(_moved_at) = var.moved_at { return Err(compile::Error::new( @@ -195,7 +200,7 @@ impl<'hir> Scopes<'hir> { Err(compile::Error::msg( span, - format_args!("Missing variable `{name}` to take"), + try_format!("Missing variable `{name}` to take"), )) } @@ -223,7 +228,7 @@ impl<'hir> Scopes<'hir> { layer.total += 1; layer.local += 1; - layer.variables.insert(name, local); + layer.variables.try_insert(name, local)?; Ok(offset) } @@ -278,7 +283,7 @@ impl<'hir> Scopes<'hir> { if self.layers.len() != expected { return Err(compile::Error::msg( span, - format_args!( + try_format!( "Scope guard mismatch, {} (actual) != {} (expected)", self.layers.len(), expected @@ -307,7 +312,7 @@ impl<'hir> Scopes<'hir> { }; tracing::trace!(?layer); - Ok(self.push(layer.child())) + Ok(self.push(layer.child())?) } /// Get the total var count of the top scope. @@ -329,8 +334,8 @@ impl<'hir> Scopes<'hir> { } /// Push a scope and return an index. - pub(crate) fn push(&mut self, layer: Layer<'hir>) -> ScopeGuard { - self.layers.push(layer); - ScopeGuard(self.layers.len()) + pub(crate) fn push(&mut self, layer: Layer<'hir>) -> alloc::Result { + self.layers.try_push(layer)?; + Ok(ScopeGuard(self.layers.len())) } } diff --git a/crates/rune/src/compile/with_span.rs b/crates/rune/src/compile/with_span.rs index 4ab4e92e2..75614c7f7 100644 --- a/crates/rune/src/compile/with_span.rs +++ b/crates/rune/src/compile/with_span.rs @@ -8,30 +8,44 @@ use crate::ast::{Span, Spanned}; /// This has a blanked implementation over [`Result`]. pub trait WithSpan { /// Convert the given result into a result which produces a spanned error. - fn with_span(self, spanned: S) -> Result> + fn with_span(self, spanned: S) -> Result> where S: Spanned; } impl WithSpan for Result { /// Attach the span extracted from `spanned` to the error if it is present. - fn with_span(self, spanned: S) -> Result> + fn with_span(self, span: S) -> Result> where S: Spanned, { match self { Ok(value) => Ok(value), - Err(error) => Err(HasSpan { - span: spanned.span(), - error, - }), + Err(error) => Err(HasSpan::new(span, error)), } } } /// An error with an associated span. #[derive(Debug)] -pub struct HasSpan { - pub(crate) span: Span, - pub(crate) error: E, +pub struct HasSpan { + span: S, + error: E, +} + +impl HasSpan { + pub(crate) fn new(span: S, error: E) -> Self { + Self { span, error } + } + + pub(crate) fn span(&self) -> Span + where + S: Spanned, + { + self.span.span() + } + + pub(crate) fn into_inner(self) -> E { + self.error + } } diff --git a/crates/rune/src/diagnostics.rs b/crates/rune/src/diagnostics.rs index 0e0bcec7a..d70bc338b 100644 --- a/crates/rune/src/diagnostics.rs +++ b/crates/rune/src/diagnostics.rs @@ -27,7 +27,7 @@ //! } //! //! let unit = result?; -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` use crate::no_std::prelude::*; @@ -93,7 +93,7 @@ impl Mode { /// let mut writer = StandardStream::stderr(ColorChoice::Always); /// diagnostics.emit(&mut writer, &sources)?; /// } -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Debug)] pub struct Diagnostics { diff --git a/crates/rune/src/doc/artifacts.rs b/crates/rune/src/doc/artifacts.rs index b1021aa98..0318f3b76 100644 --- a/crates/rune/src/doc/artifacts.rs +++ b/crates/rune/src/doc/artifacts.rs @@ -1,9 +1,13 @@ -use crate::no_std::path::Path; -use crate::no_std::borrow::Cow; +use rust_alloc::string::ToString; + use crate::no_std::io; -use crate::no_std::prelude::*; +use rust_alloc::borrow::ToOwned; +use std::path::Path; + +use crate::alloc::borrow::Cow; use crate::compile::ItemBuf; +use crate::alloc::{String, Vec}; use base64::display::Base64Display; use base64::engine::general_purpose::URL_SAFE_NO_PAD; @@ -106,10 +110,10 @@ impl Artifacts { path.as_ref().to_owned() }; - self.assets.push(Asset { + self.assets.try_push(Asset { path: path.clone(), content, - }); + })?; Ok(path) } diff --git a/crates/rune/src/doc/build.rs b/crates/rune/src/doc/build.rs index f9f755da5..3e2f9ccf6 100644 --- a/crates/rune/src/doc/build.rs +++ b/crates/rune/src/doc/build.rs @@ -3,21 +3,26 @@ mod type_; mod markdown; mod js; -use core::fmt::{self, Write}; +use core::fmt; use core::str; -use crate::no_std::prelude::*; -use crate::no_std::borrow::Cow; -use crate::no_std::collections::VecDeque; +use rust_alloc::string::ToString; use anyhow::{anyhow, bail, Context as _, Result}; use relative_path::{RelativePath, RelativePathBuf}; -use rust_embed::RustEmbed; use serde::{Serialize, Serializer}; use syntect::highlighting::ThemeSet; use syntect::html::{self, ClassStyle, ClassedHTMLGenerator}; use syntect::parsing::{SyntaxReference, SyntaxSet}; +use crate as rune; +use crate::std; +use crate::std::borrow::ToOwned; +use crate::alloc::{self, String, VecDeque, Vec}; +use crate::alloc::prelude::*; +use crate::alloc::fmt::TryWrite; +use crate::alloc::borrow::Cow; +use crate::alloc::try_format; use crate::compile::{ComponentRef, Item, ItemBuf}; use crate::doc::context::{Function, Kind, Signature, Meta}; use crate::doc::templating; @@ -37,21 +42,28 @@ const RUNEDOC_CSS: &str = "runedoc.css"; pub(crate) struct Builder<'m> { state: State, - builder: Box) -> Result + 'm>, + builder: rust_alloc::boxed::Box) -> Result + 'm>, } impl<'m> Builder<'m> { - fn new(cx: &Ctxt<'_, '_>, builder: B) -> Self where B: FnOnce(&Ctxt<'_, '_>) -> Result + 'm { - Self { - state: cx.state.clone(), - builder: Box::new(builder), - } + fn new(cx: &Ctxt<'_, '_>, builder: B) -> alloc::Result where B: FnOnce(&Ctxt<'_, '_>) -> Result + 'm { + Ok(Self { + state: cx.state.try_clone()?, + builder: rust_alloc::boxed::Box::new(builder), + }) } } -#[derive(RustEmbed)] -#[folder = "src/doc/static"] -struct Assets; +mod embed { + use rust_alloc::string::String; + use rust_alloc::boxed::Box; + + use rust_embed::RustEmbed; + + #[derive(RustEmbed)] + #[folder = "src/doc/static"] + pub(super) struct Assets; +} /// Build documentation based on the given context and visitors. pub(crate) fn build( @@ -77,7 +89,7 @@ pub(crate) fn build( let mut css = Vec::new(); let mut js = Vec::new(); - for file in Assets::iter() { + for file in embed::Assets::iter() { let path = RelativePath::new(file.as_ref()); let out = match path.extension() { @@ -87,21 +99,22 @@ pub(crate) fn build( _ => continue, }; - let file = Assets::get(file.as_ref()).context("missing asset")?; - let builder_path = artifacts.asset(true, path, move || Ok(file.data))?; - paths.insert(path.as_str(), builder_path.as_str()); - out.push(builder_path); + let file = embed::Assets::get(file.as_ref()).context("missing asset")?; + let data = Cow::try_from(file.data)?; + let builder_path = artifacts.asset(true, path, move || Ok(data))?; + paths.insert(path.as_str(), builder_path.as_str())?; + out.try_push(builder_path)?; } let theme = theme_set.themes.get(THEME).context("missing theme")?; let syntax_css = artifacts.asset(true, "syntax.css", || { - let content = html::css_for_theme_with_class_style(theme, html::ClassStyle::Spaced)?; + let content = String::try_from(html::css_for_theme_with_class_style(theme, html::ClassStyle::Spaced)?)?; Ok(content.into_bytes().into()) })?; - paths.insert("syntax.css", syntax_css.as_str()); - css.push(syntax_css); + paths.insert("syntax.css", syntax_css.as_str())?; + css.try_push(syntax_css)?; let runedoc_css = artifacts.asset(true, RUNEDOC_CSS, || { let runedoc = compile(&templating, "runedoc.css.hbs")?; @@ -109,15 +122,16 @@ pub(crate) fn build( Ok(string.into_bytes().into()) })?; - paths.insert(RUNEDOC_CSS, runedoc_css.as_str()); - css.push(runedoc_css); + paths.insert(RUNEDOC_CSS, runedoc_css.as_str())?; + css.try_push(runedoc_css)?; // Collect an ordered set of modules, so we have a baseline of what to render when. let mut initial = VecDeque::new(); for item in context.iter_modules() { - let meta = context.meta(&item).into_iter().find(|m| matches!(&m.kind, Kind::Module)).with_context(|| anyhow!("Missing meta for {item}"))?; - initial.push_back(Build::Module(meta)); + let item = item?; + let meta = context.meta(&item)?.into_iter().find(|m| matches!(&m.kind, Kind::Module)).with_context(|| anyhow!("Missing meta for {item}"))?; + initial.try_push_back(Build::Module(meta))?; } let search_index = RelativePath::new("index.js"); @@ -141,7 +155,7 @@ pub(crate) fn build( tests: Vec::new(), }; - let mut queue = initial.into_iter().collect::>(); + let mut queue = initial.into_iter().try_collect::>()?; let mut modules = Vec::new(); let mut builders = Vec::new(); @@ -151,34 +165,34 @@ pub(crate) fn build( Build::Type(meta) => { cx.set_path(meta)?; let (builder, items) = self::type_::build(&mut cx, "Type", "type", meta)?; - builders.push(builder); - cx.index.extend(items); + builders.try_push(builder)?; + cx.index.try_extend(items)?; } Build::Struct(meta) => { cx.set_path(meta)?; let (builder, index) = self::type_::build(&mut cx, "Struct", "struct", meta)?; - builders.push(builder); - cx.index.extend(index); + builders.try_push(builder)?; + cx.index.try_extend(index)?; } Build::Enum(meta) => { cx.set_path(meta)?; let (builder, index) = self::enum_::build(&mut cx, meta)?; - builders.push(builder); - cx.index.extend(index); + builders.try_push(builder)?; + cx.index.try_extend(index)?; } Build::Macro(meta) => { cx.set_path(meta)?; - builders.push(build_macro(&mut cx, meta)?); + builders.try_push(build_macro(&mut cx, meta)?)?; } Build::Function(meta) => { cx.set_path(meta)?; - builders.push(build_function(&mut cx, meta)?); + builders.try_push(build_function(&mut cx, meta)?)?; } Build::Module(meta) => { cx.set_path(meta)?; - builders.push(module(&mut cx, meta, &mut queue)?); + builders.try_push(module(&mut cx, meta, &mut queue)?)?; let item = meta.item.context("Missing item")?; - modules.push((item, cx.state.path.clone())); + modules.try_push((item, cx.state.path.clone()))?; } } } @@ -191,11 +205,11 @@ pub(crate) fn build( cx.search_index = Some(&search_index_path); cx.state.path = RelativePath::new("index.html").to_owned(); - builders.push(build_index(&cx, modules)?); + builders.try_push(build_index(&cx, modules)?)?; for builder in builders { cx.state = builder.state; - artifacts.asset(false, &cx.state.path, || Ok((builder.builder)(&cx)?.into_bytes().into()))?; + artifacts.asset(false, &cx.state.path, || Ok((builder.builder)(&cx)?.into_bytes().try_into()?))?; } artifacts.set_tests(cx.tests); @@ -211,7 +225,7 @@ fn build_search_index(cx: &Ctxt) -> Result { write!(s, "[\"{path}\",\"{item}\",\"{kind}\",\"")?; if let Some(doc) = doc { - js::encode_quoted(&mut s, doc); + js::encode_quoted(&mut s, doc)?; } write!(s, "\"]")?; @@ -282,8 +296,9 @@ pub(crate) struct IndexEntry<'m> { pub(crate) doc: Option, } -#[derive(Default, Clone)] +#[derive(Default, TryClone)] pub(crate) struct State { + #[try_clone(with = RelativePathBuf::clone)] path: RelativePathBuf, item: ItemBuf, } @@ -323,18 +338,18 @@ impl<'m> Ctxt<'_, 'm> { let item = meta.item.context("Missing meta item")?; self.state.path = RelativePathBuf::new(); - self.state.item = item.to_owned(); + self.state.item = item.try_to_owned()?; build_item_path(self.name, item, item_kind, &mut self.state.path)?; let doc = self.render_line_docs(meta, meta.docs.get(..1).unwrap_or_default())?; - self.index.push(IndexEntry { + self.index.try_push(IndexEntry { path: self.state.path.clone(), item: Cow::Borrowed(item), kind: IndexKind::Item(item_kind), doc, - }); + })?; Ok(()) } @@ -343,16 +358,16 @@ impl<'m> Ctxt<'_, 'm> { self.state.path.parent().unwrap_or(RelativePath::new("")) } - fn shared(&self) -> Shared<'_> { + fn shared(&self) -> Result> { let dir = self.dir(); - Shared { + Ok(Shared { data_path: self.state.path.parent(), search_index: self.search_index.map(|p| dir.relative(p)), - fonts: self.fonts.iter().map(|f| dir.relative(f)).collect(), - css: self.css.iter().map(|f| dir.relative(f)).collect(), - js: self.js.iter().map(|f| dir.relative(f)).collect(), - } + fonts: self.fonts.iter().map(|f| dir.relative(f)).try_collect()?, + css: self.css.iter().map(|f| dir.relative(f)).try_collect()?, + js: self.js.iter().map(|f| dir.relative(f)).try_collect()?, + }) } /// Render rust code. @@ -366,7 +381,7 @@ impl<'m> Ctxt<'_, 'm> { None => self.syntax_set.find_syntax_plain_text(), }; - Ok(format!( + Ok(try_format!( "

{}
", render_code_by_syntax(&self.syntax_set, lines, syntax, None)? )) @@ -386,7 +401,6 @@ impl<'m> Ctxt<'_, 'm> { S: AsRef, { use pulldown_cmark::{Options, Parser, BrokenLink}; - use std::fmt::Write; if docs.is_empty() { return Ok(None); @@ -397,8 +411,8 @@ impl<'m> Ctxt<'_, 'm> { for line in docs { let line = line.as_ref(); let line = line.strip_prefix(' ').unwrap_or(line); - input.push_str(line); - input.push('\n'); + input.try_push_str(line)?; + input.try_push('\n')?; } let mut o = String::new(); @@ -406,9 +420,18 @@ impl<'m> Ctxt<'_, 'm> { let mut options = Options::empty(); options.insert(Options::ENABLE_STRIKETHROUGH); + let mut link_error = None; + let mut callback = |link: BrokenLink<'_>| { - let (path, title) = self.link_callback(meta, link.reference.as_ref())?; - Some((path.to_string().into(), title.into())) + let (path, title) = match self.link_callback(meta, link.reference.as_ref()) { + Ok(out) => out?, + Err(error) => { + link_error = Some(error); + return None; + } + }; + + Some((path.to_string().into(), title.into_std().into())) }; let iter = Parser::new_with_broken_link_callback(&input, options, Some(&mut callback)); @@ -417,13 +440,17 @@ impl<'m> Ctxt<'_, 'm> { markdown::push_html(&self.syntax_set, &mut o, iter, capture_tests.then_some(&mut tests))?; + if let Some(error) = link_error { + return Err(error); + } + if capture_tests && !tests.is_empty() { for (content, params) in tests { - self.tests.push(Test { - item: self.state.item.clone(), + self.tests.try_push(Test { + item: self.state.item.try_clone()?, content, params, - }); + })?; } } @@ -448,7 +475,7 @@ impl<'m> Ctxt<'_, 'm> { while iter.next_back().is_some() { if let Some(name) = iter.as_item().last() { let url = self.item_path(iter.as_item(), ItemKind::Module)?; - module.push(format!("{name}")); + module.try_push(try_format!("{name}"))?; } } @@ -456,11 +483,26 @@ impl<'m> Ctxt<'_, 'm> { if is_module { if let Some(name) = item.last() { - module.push(format!("{name}")); + module.try_push(try_format!("{name}"))?; } } - Ok(module.join("::")) + let mut string = String::new(); + + let mut it = module.into_iter(); + + let last = it.next_back(); + + for c in it { + string.try_push_str(c.as_str())?; + string.try_push_str("::")?; + } + + if let Some(c) = last { + string.try_push_str(c.as_str())?; + } + + Ok(string) } /// Convert a hash into a link. @@ -475,16 +517,16 @@ impl<'m> Ctxt<'_, 'm> { } } - let mut it = self.context.meta_by_hash(hash).into_iter().flat_map(|m| Some((m, into_item_kind(m)?))); + let mut it = self.context.meta_by_hash(hash)?.into_iter().flat_map(|m| Some((m, into_item_kind(m)?))); let Some((meta, kind)) = it.next() else { tracing::warn!(?hash, "No link for hash"); - for meta in self.context.meta_by_hash(hash) { + for meta in self.context.meta_by_hash(hash)? { tracing::warn!("Candidate: {:?}", meta.kind); } - return Ok(Some(format!("{hash}"))) + return Ok(Some(try_format!("{hash}"))) }; let item = meta.item.context("Missing item link meta")?; @@ -498,7 +540,7 @@ impl<'m> Ctxt<'_, 'm> { }; let path = self.item_path(item, kind)?; - Ok(Some(format!("{name}"))) + Ok(Some(try_format!("{name}"))) } /// Coerce args into string. @@ -510,7 +552,6 @@ impl<'m> Ctxt<'_, 'm> { argument_types: &[Option], ) -> Result { use std::borrow::Cow; - use std::fmt::Write; let mut string = String::new(); let mut types = argument_types.iter(); @@ -575,20 +616,20 @@ impl<'m> Ctxt<'_, 'm> { if arg == "self" { if let Some(Some(hash)) = types.next() { if let Some(link) = self.link(*hash, Some("self"))? { - string.push_str(&link); + string.try_push_str(&link)?; } else { - string.push_str("self"); + string.try_push_str("self")?; } } else { - string.push_str("self"); + string.try_push_str("self")?; } } else { - string.push_str(arg.as_ref()); + string.try_push_str(arg.as_ref())?; if let Some(Some(hash)) = types.next() { if let Some(link) = self.link(*hash, None)? { - string.push_str(": "); - string.push_str(&link); + string.try_push_str(": ")?; + string.try_push_str(&link)?; } } } @@ -601,7 +642,7 @@ impl<'m> Ctxt<'_, 'm> { Ok(string) } - fn link_callback(&self, meta: Meta<'_>, link: &str) -> Option<(RelativePathBuf, String)> { + fn link_callback(&self, meta: Meta<'_>, link: &str) -> Result> { enum Flavor { Any, Macro, @@ -641,17 +682,25 @@ impl<'m> Ctxt<'_, 'm> { let link = link.trim_matches(|c| matches!(c, '`')); let (link, flavor) = flavor(link); + let Some(item) = meta.item else { + return Ok(None); + }; + let item = if matches!(meta.kind, Kind::Module) { - meta.item?.join([link]) + item.join([link])? } else { - meta.item?.parent()?.join([link]) + let Some(parent) = item.parent() else { + return Ok(None); + }; + + parent.join([link])? }; let item_path = 'out: { let mut alts = Vec::new(); - for meta in self.context.meta(&item) { - alts.push(match meta.kind { + for meta in self.context.meta(&item)? { + alts.try_push(match meta.kind { Kind::Struct if flavor.is_struct() => ItemKind::Struct, Kind::Enum if flavor.is_enum() => ItemKind::Enum, Kind::Macro if flavor.is_macro() => ItemKind::Macro, @@ -659,7 +708,7 @@ impl<'m> Ctxt<'_, 'm> { _ => { continue; }, - }); + })?; } match &alts[..] { @@ -672,12 +721,12 @@ impl<'m> Ctxt<'_, 'm> { } } - return None; + return Ok(None); }; - let path = self.item_path(&item, item_path).ok()?; - let title = format!("{item_path} {link}"); - Some((path, title)) + let path = self.item_path(&item, item_path)?; + let title = try_format!("{item_path} {link}"); + Ok(Some((path, title))) } } @@ -692,11 +741,11 @@ enum Build<'a> { /// Get an asset as a string. fn asset_str(path: &str) -> Result> { - let asset = Assets::get(path).with_context(|| anyhow!("{path}: missing asset"))?; + let asset = embed::Assets::get(path).with_context(|| anyhow!("{path}: missing asset"))?; let data = match asset.data { - Cow::Borrowed(data) => Cow::Borrowed(str::from_utf8(data).with_context(|| anyhow!("{path}: not utf-8"))?), - Cow::Owned(data) => Cow::Owned(String::from_utf8(data).with_context(|| anyhow!("{path}: not utf-8"))?), + rust_alloc::borrow::Cow::Borrowed(data) => Cow::Borrowed(str::from_utf8(data).with_context(|| anyhow!("{path}: not utf-8"))?), + rust_alloc::borrow::Cow::Owned(data) => Cow::Owned(String::from_utf8(data.try_into()?).with_context(|| anyhow!("{path}: not utf-8"))?), }; Ok(data) @@ -739,15 +788,15 @@ fn build_index<'m>(cx: &Ctxt<'_, 'm>, mods: Vec<(&'m Item, RelativePathBuf)>) -> continue; } - modules.push(Module { item, path }); + modules.try_push(Module { item, path })?; } Ok(Builder::new(cx, move |cx| { cx.index_template.render(&Params { - shared: cx.shared(), + shared: cx.shared()?, modules, }) - })) + })?) } /// Build a single module. @@ -841,69 +890,69 @@ fn module<'m>(cx: &mut Ctxt<'_, 'm>, meta: Meta<'m>, queue: &mut VecDeque { - queue.push_front(Build::Type(m)); + queue.try_push_front(Build::Type(m))?; let path = cx.item_path(&item, ItemKind::Type)?; - types.push(Type { - item: item.clone(), + types.try_push(Type { + item: item.try_clone()?, path, name, doc: cx.render_line_docs(m, m.docs.get(..1).unwrap_or_default())?, - }); + })?; } Kind::Struct { .. } => { - queue.push_front(Build::Struct(m)); + queue.try_push_front(Build::Struct(m))?; let path = cx.item_path(&item, ItemKind::Struct)?; - structs.push(Struct { - item: item.clone(), + structs.try_push(Struct { + item: item.try_clone()?, path, name, doc: cx.render_line_docs(m, m.docs.get(..1).unwrap_or_default())?, - }); + })?; } Kind::Enum { .. } => { - queue.push_front(Build::Enum(m)); + queue.try_push_front(Build::Enum(m))?; let path = cx.item_path(&item, ItemKind::Enum)?; - enums.push(Enum { - item: item.clone(), + enums.try_push(Enum { + item: item.try_clone()?, path, name, doc: cx.render_line_docs(m, m.docs.get(..1).unwrap_or_default())?, - }); + })?; } Kind::Macro => { let item = m.item.context("Missing macro item")?; - queue.push_front(Build::Macro(m)); + queue.try_push_front(Build::Macro(m))?; - macros.push(Macro { + macros.try_push(Macro { path: cx.item_path(item, ItemKind::Macro)?, item, name, doc: cx.render_line_docs(m, m.docs.get(..1).unwrap_or_default())?, - }); + })?; } Kind::Function(f) => { if matches!(f.signature, Signature::Instance { .. }) { continue; } - queue.push_front(Build::Function(m)); + queue.try_push_front(Build::Function(m))?; - functions.push(Function { + functions.try_push(Function { is_async: f.is_async, deprecated: f.deprecated, path: cx.item_path(&item, ItemKind::Function)?, - item: item.clone(), + item: item.try_clone()?, name, args: cx.args_to_string(f.arg_names, f.args, f.signature, f.argument_types)?, doc: cx.render_line_docs(m, m.docs.get(..1).unwrap_or_default())?, - }); + })?; } Kind::Module => { let item = m.item.context("Missing module item")?; @@ -913,13 +962,13 @@ fn module<'m>(cx: &mut Ctxt<'_, 'm>, meta: Meta<'m>, queue: &mut VecDeque { continue; @@ -932,7 +981,7 @@ fn module<'m>(cx: &mut Ctxt<'_, 'm>, meta: Meta<'m>, queue: &mut VecDeque(cx: &mut Ctxt<'_, 'm>, meta: Meta<'m>, queue: &mut VecDeque(cx: &mut Ctxt<'_, 'm>, meta: Meta<'m>) -> Result> Ok(Builder::new(cx, move |cx| { cx.macro_template.render(&Params { - shared: cx.shared(), + shared: cx.shared()?, module: cx.module_path_html(meta, false)?, item, name, doc, }) - })) + })?) } /// Build a function. @@ -1015,7 +1064,7 @@ fn build_function<'m>(cx: &mut Ctxt<'_, 'm>, meta: Meta<'m>) -> Result(cx: &mut Ctxt<'_, 'm>, meta: Meta<'m>) -> Result(cx: &mut Ctxt<'_, 'm>, meta: Meta<'m>) -> Result<(Builde let builder = Builder::new(cx, move |cx| { cx.enum_template.render(&Params { - shared: cx.shared(), + shared: cx.shared()?, module, name, item, @@ -44,7 +43,7 @@ pub(crate) fn build<'m>(cx: &mut Ctxt<'_, 'm>, meta: Meta<'m>) -> Result<(Builde protocols, doc, }) - }); + })?; Ok((builder, index)) } diff --git a/crates/rune/src/doc/build/js.rs b/crates/rune/src/doc/build/js.rs index 1957b0693..858950d76 100644 --- a/crates/rune/src/doc/build/js.rs +++ b/crates/rune/src/doc/build/js.rs @@ -1,17 +1,19 @@ -use crate::no_std::prelude::*; +use crate::alloc::{self, String}; /// Encode `string` as part of a quoted javascript string. -pub(crate) fn encode_quoted(out: &mut String, string: &str) { +pub(crate) fn encode_quoted(out: &mut String, string: &str) -> alloc::Result<()> { for c in string.chars() { let s = match c { '\\' => "\\\\", '\"' => "\\\"", c => { - out.push(c); + out.try_push(c)?; continue; } }; - out.push_str(s); + out.try_push_str(s)?; } + + Ok(()) } diff --git a/crates/rune/src/doc/build/markdown.rs b/crates/rune/src/doc/build/markdown.rs index c9daeb86c..f656c9123 100644 --- a/crates/rune/src/doc/build/markdown.rs +++ b/crates/rune/src/doc/build/markdown.rs @@ -1,31 +1,43 @@ -use core::fmt::{self, Write}; - -use crate::no_std::collections::HashMap; -use crate::no_std::prelude::*; -use crate::no_std::Error; +use core::fmt; +use std::io; use crate::doc::artifacts::TestParams; +use crate::alloc::{try_vec, String, Vec, HashMap}; +use crate::alloc::fmt::TryWrite; use syntect::parsing::{SyntaxReference, SyntaxSet}; -use pulldown_cmark::escape::{escape_href, escape_html}; +use pulldown_cmark::escape::{escape_href, escape_html, StrWrite}; use pulldown_cmark::{CowStr, Alignment, CodeBlockKind, LinkType, Tag, Event}; +use anyhow::Result; pub(crate) const RUST_TOKEN: &str = "rust"; pub(crate) const RUNE_TOKEN: &str = "rune"; use Event::*; -type Result = core::result::Result; - enum TableState { Head, Body, } +struct StringWriter<'a> { + string: &'a mut String, +} + +impl StrWrite for StringWriter<'_> { + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.string.try_push_str(s).map_err(|error| io::Error::new(io::ErrorKind::Other, error)) + } + + fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { + TryWrite::write_fmt(self.string, args).map_err(|error| io::Error::new(io::ErrorKind::Other, error)) + } +} + struct Writer<'a, 'o, I> { syntax_set: &'a SyntaxSet, iter: I, - out: &'o mut String, + out: StringWriter<'o>, tests: Option<&'o mut Vec<(String, TestParams)>>, codeblock: Option<(&'a SyntaxReference, Option)>, table_state: TableState, @@ -40,7 +52,7 @@ where { #[inline] fn write(&mut self, s: &str) -> Result<()> { - self.out.write_str(s)?; + self.out.string.try_push_str(s)?; Ok(()) } @@ -62,7 +74,7 @@ where if let Some(params) = params { if let Some(tests) = self.tests.as_mut() { - tests.push((string, params)); + tests.try_push((string, params))?; } } @@ -93,7 +105,7 @@ where self.write("")?; - let number = *self.numbers.entry(name).or_insert(len); + let number = *self.numbers.entry(name).or_try_insert(len)?; write!(&mut self.out, "{}", number)?; self.write("")?; } @@ -140,7 +152,7 @@ where self.write(">")?; } Tag::Table(alignments) => { - self.table_alignments = alignments; + self.table_alignments = alignments.try_into()?; self.write("")?; } Tag::TableHead => { @@ -246,7 +258,7 @@ where escape_html(&mut self.out, &name).map_err(|_| fmt::Error)?; self.write("\">")?; let len = self.numbers.len() + 1; - let number = *self.numbers.entry(name).or_insert(len); + let number = *self.numbers.entry(name).or_try_insert(len)?; write!(&mut self.out, "{}", number)?; self.write("")?; } @@ -387,8 +399,8 @@ where } FootnoteReference(name) => { let len = self.numbers.len() + 1; - let number = *self.numbers.entry(name).or_insert(len); - write!(&mut self.out, "[{}]", number)?; + let number = *self.numbers.entry(name).or_try_insert(len)?; + write!(self.out, "[{}]", number)?; } TaskListMarker(true) => self.write("[x]")?, TaskListMarker(false) => self.write("[ ]")?, @@ -400,18 +412,18 @@ where } /// Process markdown html and captures tests. -pub(super) fn push_html<'a, I>(syntax_set: &'a SyntaxSet, out: &'a mut String, iter: I, tests: Option<&'a mut Vec<(String, TestParams)>>) -> Result<()> +pub(super) fn push_html<'a, I>(syntax_set: &'a SyntaxSet, string: &'a mut String, iter: I, tests: Option<&'a mut Vec<(String, TestParams)>>) -> Result<()> where I: Iterator>, { let writer = Writer { syntax_set, iter, - out, + out: StringWriter { string }, tests, codeblock: None, table_state: TableState::Head, - table_alignments: vec![], + table_alignments: try_vec![], table_cell_index: 0, numbers: HashMap::new(), }; diff --git a/crates/rune/src/doc/build/type_.rs b/crates/rune/src/doc/build/type_.rs index dfc8c1527..6c0700e24 100644 --- a/crates/rune/src/doc/build/type_.rs +++ b/crates/rune/src/doc/build/type_.rs @@ -1,9 +1,9 @@ -use crate::no_std::prelude::*; -use crate::no_std::borrow::Cow; - use anyhow::{Context, Result}; use serde::Serialize; +use crate::alloc::{Vec, String}; +use crate::alloc::borrow::Cow; +use crate::alloc::prelude::*; use crate::compile::{ComponentRef, Item}; use crate::doc::context::{Assoc, AssocFnKind, Meta}; use crate::doc::build::{Ctxt, IndexEntry, IndexKind, Builder}; @@ -51,11 +51,11 @@ pub(super) fn build_assoc_fns<'m>( let line_doc = cx.render_line_docs(meta, variant.docs.get(..1).unwrap_or_default())?; let doc = cx.render_docs(meta, variant.docs, true)?; - variants.push(Variant { + variants.try_push(Variant { name: variant.name, line_doc, doc, - }); + })?; } Assoc::Fn(assoc) => { let value; @@ -73,23 +73,23 @@ pub(super) fn build_assoc_fns<'m>( AssocFnKind::Method(name, args, sig) => { let line_doc = cx.render_line_docs(meta, assoc.docs.get(..1).unwrap_or_default())?; - cx.state.item.push(name); + cx.state.item.push(name)?; let doc = cx.render_docs(meta, assoc.docs, true)?; - cx.state.item.pop(); + cx.state.item.pop()?; let mut list = Vec::new(); for &hash in assoc.parameter_types { if let Some(link) = cx.link(hash, None)? { - list.push(link); + list.try_push(link)?; } else { - list.push(hash.to_string()); + list.try_push(hash.try_to_string()?)?; } } - - let parameters = (!list.is_empty()).then(|| list.join(", ")); - - methods.push(Method { + + let parameters = (!list.is_empty()).then(|| list.iter().try_join(", ")).transpose()?; + + methods.try_push(Method { is_async: assoc.is_async, deprecated: assoc.deprecated, name, @@ -106,7 +106,7 @@ pub(super) fn build_assoc_fns<'m>( }, line_doc, doc, - }); + })?; continue; } @@ -124,7 +124,7 @@ pub(super) fn build_assoc_fns<'m>( None }; - protocols.push(Protocol { + protocols.try_push(Protocol { name: protocol.name, repr, return_type: match assoc.return_type { @@ -132,7 +132,7 @@ pub(super) fn build_assoc_fns<'m>( None => None, }, doc, - }); + })?; } } } @@ -140,24 +140,24 @@ pub(super) fn build_assoc_fns<'m>( let mut index = Vec::new(); if let Some(name) = cx.state.path.file_name() { - index.reserve(methods.len()); + index.try_reserve(methods.len())?; for m in &methods { - index.push(IndexEntry { + index.try_push(IndexEntry { path: cx.state.path.with_file_name(format!("{name}#method.{}", m.name)), - item: Cow::Owned(meta_item.join([m.name])), + item: Cow::Owned(meta_item.join([m.name])?), kind: IndexKind::Method, - doc: m.line_doc.clone(), - }); + doc: m.line_doc.try_clone()?, + })?; } for m in &variants { - index.push(IndexEntry { + index.try_push(IndexEntry { path: cx.state.path.with_file_name(format!("{name}#variant.{}", m.name)), - item: Cow::Owned(meta_item.join([m.name])), + item: Cow::Owned(meta_item.join([m.name])?), kind: IndexKind::Variant, - doc: m.line_doc.clone(), - }); + doc: m.line_doc.try_clone()?, + })?; } } @@ -193,7 +193,7 @@ pub(crate) fn build<'m>(cx: &mut Ctxt<'_, 'm>, what: &'static str, what_class: & let builder = Builder::new(cx, move |cx| { cx.type_template.render(&Params { - shared: cx.shared(), + shared: cx.shared()?, what, what_class, module, @@ -203,7 +203,7 @@ pub(crate) fn build<'m>(cx: &mut Ctxt<'_, 'm>, what: &'static str, what_class: & protocols, doc, }) - }); + })?; Ok((builder, index)) } diff --git a/crates/rune/src/doc/context.rs b/crates/rune/src/doc/context.rs index a5babdcba..c4f02d9f1 100644 --- a/crates/rune/src/doc/context.rs +++ b/crates/rune/src/doc/context.rs @@ -1,5 +1,5 @@ -use crate::no_std::prelude::*; - +use crate::alloc::{self, String, Vec}; +use crate::alloc::prelude::*; use crate::compile::context::ContextMeta; use crate::compile::{meta, ComponentRef, IntoComponent, Item, ItemBuf}; use crate::doc::{Visitor, VisitorData}; @@ -240,50 +240,58 @@ impl<'a> Context<'a> { pub(crate) fn iter_components( &self, iter: I, - ) -> impl Iterator, ComponentRef<'a>)> + 'a + ) -> alloc::Result, ComponentRef<'a>)> + 'a> where I: 'a + Clone + IntoIterator, I::Item: IntoComponent, { - let tail = self.context.iter_components(iter.clone()).map(|n| (MetaSource::Context, n)); - self.visitors - .iter() - .flat_map(move |v| v.names.iter_components(iter.clone()).map(|n| (MetaSource::Source(&v.base), n))) - .chain(tail) + let mut out = Vec::new(); + + for c in self.context.iter_components(iter.clone())? { + out.try_push((MetaSource::Context, c))?; + } + + for v in self.visitors { + for c in v.names.iter_components(iter.clone())? { + out.try_push((MetaSource::Source(&v.base), c))?; + } + } + + Ok(out.into_iter()) } /// Get all matching meta items by hash. - pub(crate) fn meta_by_hash(&self, hash: Hash) -> Vec> { + pub(crate) fn meta_by_hash(&self, hash: Hash) -> alloc::Result>> { let mut out = Vec::new(); for visitor in self.visitors { if let Some(data) = visitor.get_by_hash(hash) { - out.push(visitor_meta_to_meta(&visitor.base, data)); + out.try_push(visitor_meta_to_meta(&visitor.base, data))?; } } for meta in self.context.lookup_meta_by_hash(hash) { - out.extend(self.context_meta_to_meta(meta)); + out.try_extend(self.context_meta_to_meta(meta))?; } - out + Ok(out) } /// Lookup all meta matching the given item. - pub(crate) fn meta(&self, item: &Item) -> Vec> { + pub(crate) fn meta(&self, item: &Item) -> alloc::Result>> { let mut out = Vec::new(); for visitor in self.visitors { if let Some(data) = visitor.get(item) { - out.push(visitor_meta_to_meta(&visitor.base, data)); + out.try_push(visitor_meta_to_meta(&visitor.base, data))?; } } for meta in self.context.lookup_meta(item).into_iter().flatten() { - out.extend(self.context_meta_to_meta(meta)); + out.try_extend(self.context_meta_to_meta(meta))?; } - out + Ok(out) } fn context_meta_to_meta(&self, meta: &'a ContextMeta) -> Option> { @@ -341,10 +349,10 @@ impl<'a> Context<'a> { } /// Iterate over known modules. - pub(crate) fn iter_modules(&self) -> impl IntoIterator + '_ { + pub(crate) fn iter_modules(&self) -> impl IntoIterator> + '_ { self.visitors .iter() - .map(|v| v.base.clone()) + .map(|v| v.base.try_clone()) .chain(self.context.iter_crates().map(ItemBuf::with_crate)) } } diff --git a/crates/rune/src/doc/templating.rs b/crates/rune/src/doc/templating.rs index 03d5e75fd..2473bf75f 100644 --- a/crates/rune/src/doc/templating.rs +++ b/crates/rune/src/doc/templating.rs @@ -1,16 +1,16 @@ -use std::sync::Mutex; - -use crate::no_std::collections::HashMap; -use crate::no_std::prelude::*; +use crate::std::sync::Mutex; use crate::no_std::sync::Arc; -use crate::no_std::borrow::Cow; +use crate::no_std::std; +use crate::alloc::{self, String, HashMap}; +use crate::alloc::borrow::Cow; +use crate::alloc::prelude::*; use handlebars::{ Context, Handlebars, Helper, HelperResult, Output, RenderContext, Renderable, StringOutput, HelperDef, }; use serde::Serialize; -use crate::Result; +use crate::support::Result; /// A compiled template. pub(crate) struct Template { @@ -29,7 +29,7 @@ impl Template { let mut out = StringOutput::new(); self.template .render(&self.handlebars, &cx, &mut render_context, &mut out)?; - Ok(out.into_string()?) + Ok(out.into_string()?.try_into()?) } } @@ -40,8 +40,9 @@ pub(crate) struct Paths { impl Paths { /// Insert a path redirect. - pub(crate) fn insert(&self, from: &str, to: &str) { - self.inner.lock().unwrap().insert(from.to_owned(), to.to_owned()); + pub(crate) fn insert(&self, from: &str, to: &str) -> alloc::Result<()> { + self.inner.lock().unwrap().try_insert(from.try_to_owned()?, to.try_to_owned()?)?; + Ok(()) } } @@ -54,8 +55,8 @@ impl Templating { /// Set up a new templating engine. pub(crate) fn new<'a, I>(partials: I, paths: Paths) -> Result where I: IntoIterator)> { let mut handlebars = Handlebars::new(); - handlebars.register_helper("literal", Box::new(literal)); - handlebars.register_helper("path", Box::new(path(paths))); + handlebars.register_helper("literal", std::Box::new(literal)); + handlebars.register_helper("path", std::Box::new(path(paths))); for (name, source) in partials { handlebars.register_partial(name, source.as_ref())?; diff --git a/crates/rune/src/doc/visitor.rs b/crates/rune/src/doc/visitor.rs index dccbdb53e..45d6f4147 100644 --- a/crates/rune/src/doc/visitor.rs +++ b/crates/rune/src/doc/visitor.rs @@ -1,12 +1,12 @@ -use crate::no_std::prelude::*; -use crate::no_std::collections::{hash_map, HashMap}; - +use crate::alloc::prelude::*; +use crate::alloc::{Box, Vec, String}; +use crate::alloc::hash_map::{self, HashMap}; use crate::compile::{ MetaError, CompileVisitor, IntoComponent, Item, ItemBuf, MetaRef, Names, Located, }; use crate::compile::meta; use crate::hash::Hash; -use crate::alloc::AllocError; +use crate::alloc; pub(crate) struct VisitorData { pub(crate) item: ItemBuf, @@ -40,13 +40,13 @@ pub struct Visitor { impl Visitor { /// Construct a visitor with the given base component. - pub fn new(base: I) -> Result + pub fn new(base: I) -> alloc::Result where I: IntoIterator, I::Item: IntoComponent, { let mut this = Self { - base: base.into_iter().collect::(), + base: base.into_iter().try_collect::()?, names: Names::default(), data: HashMap::default(), item_to_hash: HashMap::new(), @@ -55,8 +55,8 @@ impl Visitor { let hash = Hash::type_hash(&this.base); this.names.insert(&this.base)?; - this.data.insert(hash, VisitorData::new(this.base.clone(), hash, Some(meta::Kind::Module))); - this.item_to_hash.insert(this.base.clone(), hash); + this.data.try_insert(hash, VisitorData::new(this.base.try_clone()?, hash, Some(meta::Kind::Module)))?; + this.item_to_hash.try_insert(this.base.try_clone()?, hash)?; Ok(this) } @@ -79,32 +79,32 @@ impl CompileVisitor for Visitor { return Ok(()); } - let item = self.base.join(meta.item); + let item = self.base.join(meta.item)?; tracing::trace!(base = ?self.base, meta = ?meta.item, ?item, "register meta"); self.names.insert(&item)?; - self.item_to_hash.insert(item.to_owned(), meta.hash); + self.item_to_hash.try_insert(item.try_to_owned()?, meta.hash)?; match self.data.entry(meta.hash) { hash_map::Entry::Occupied(e) => { - e.into_mut().kind = Some(meta.kind.clone()); + e.into_mut().kind = Some(meta.kind.try_clone()?); } hash_map::Entry::Vacant(e) => { - e.insert(VisitorData::new(item, meta.hash, Some(meta.kind.clone()))); + e.try_insert(VisitorData::new(item, meta.hash, Some(meta.kind.try_clone()?)))?; } } if let Some(container) = meta.kind.associated_container() { self.associated .entry(container) - .or_default() - .push(meta.hash); + .or_try_default()? + .try_push(meta.hash)?; } Ok(()) } - fn visit_doc_comment(&mut self, _location: &dyn Located, item: &Item, hash: Hash, string: &str) { + fn visit_doc_comment(&mut self, _location: &dyn Located, item: &Item, hash: Hash, string: &str) -> Result<(), MetaError> { // Documentation comments are literal source lines, so they're newline // terminated. Since we perform our own internal newlines conversion // these need to be trimmed - at least between each doc item. @@ -112,15 +112,16 @@ impl CompileVisitor for Visitor { matches!(c, '\n' | '\r') } - let item = self.base.join(item); + let item = self.base.join(item)?; tracing::trace!(?item, "visiting comment"); - let data = self - .data - .entry(hash) - .or_insert_with(|| VisitorData::new(item.to_owned(), hash, None)); + let data = match self.data.entry(hash) { + hash_map::Entry::Occupied(e) => e.into_mut(), + hash_map::Entry::Vacant(e) => e.try_insert(VisitorData::new(item.try_to_owned()?, hash, None))?, + }; - data.docs.push(string.trim_end_matches(newlines).to_owned()); + data.docs.try_push(string.trim_end_matches(newlines).try_to_owned()?)?; + Ok(()) } fn visit_field_doc_comment( @@ -130,17 +131,20 @@ impl CompileVisitor for Visitor { hash: Hash, field: &str, string: &str, - ) { - let item = self.base.join(item); + ) -> Result<(), MetaError> { + let item = self.base.join(item)?; tracing::trace!(?item, "visiting field comment"); - let data = self - .data - .entry(hash) - .or_insert_with(|| VisitorData::new(item.to_owned(), hash, None)); + let data = match self.data.entry(hash) { + hash_map::Entry::Occupied(e) => e.into_mut(), + hash_map::Entry::Vacant(e) => e.try_insert(VisitorData::new(item.try_to_owned()?, hash, None))?, + }; + data.field_docs - .entry(field.into()) - .or_default() - .push(string.to_owned()); + .entry(field.try_into()?) + .or_try_default()? + .try_push(string.try_to_owned()?)?; + + Ok(()) } } diff --git a/crates/rune/src/exported_macros.rs b/crates/rune/src/exported_macros.rs index 1c8eb0416..0a324ad5f 100644 --- a/crates/rune/src/exported_macros.rs +++ b/crates/rune/src/exported_macros.rs @@ -1,5 +1,9 @@ /// Helper to perform the try operation over [`VmResult`]. /// +/// This can be used through [`rune::function`] by enabling the `vm_result` +/// option and suffixing an expression with `.vm?`. +/// +/// [`rune::function`]: crate::function /// [`VmResult`]: crate::runtime::VmResult #[macro_export] macro_rules! vm_try { @@ -13,6 +17,32 @@ macro_rules! vm_try { }; } +/// Helper to cause a panic. +/// +/// This simply returns a [`VmResult`], but the macro is provided to play nicely +/// with [`rune::function`], since a regular return would otherwise be +/// transformed. +/// +/// [`rune::function`]: crate::function +/// [`VmResult`]: crate::runtime::VmResult +/// +/// # Examples +/// +/// ``` +/// #[rune::function(vm_result)] +/// fn hello(panic: bool) { +/// if panic { +/// vm_panic!("I was told to panic"); +/// } +/// } +/// ``` +#[macro_export] +macro_rules! vm_panic { + ($expr:expr) => {{ + return $crate::runtime::VmResult::panic($expr); + }}; +} + /// Helper macro to perform a `write!` in a context which errors with /// [`VmResult`] and returns `VmResult>` on write errors. /// diff --git a/crates/rune/src/fmt.rs b/crates/rune/src/fmt.rs index e26d5f73a..ae048c1f3 100644 --- a/crates/rune/src/fmt.rs +++ b/crates/rune/src/fmt.rs @@ -9,8 +9,7 @@ mod indent_writer; mod printer; mod whitespace; -use crate::no_std::prelude::*; - +use crate::alloc::Vec; use crate::ast; use crate::parse::{Parse, Parser}; use crate::SourceId; diff --git a/crates/rune/src/fmt/error.rs b/crates/rune/src/fmt/error.rs index 29ea5d9b2..62e0eeb0e 100644 --- a/crates/rune/src/fmt/error.rs +++ b/crates/rune/src/fmt/error.rs @@ -2,6 +2,7 @@ use core::fmt; use crate::no_std::io; +use crate::alloc; use crate::compile; #[derive(Debug)] @@ -10,6 +11,7 @@ pub(crate) enum FormattingError { Io(io::Error), InvalidSpan(usize, usize, usize), CompileError(compile::Error), + AllocError(alloc::Error), Eof, } @@ -21,6 +23,7 @@ impl fmt::Display for FormattingError { write!(f, "Invalid span {from}..{to} but max is {max}",) } FormattingError::CompileError(error) => error.fmt(f), + FormattingError::AllocError(error) => error.fmt(f), FormattingError::Eof {} => write!(f, "Unexpected end of input"), } } @@ -40,6 +43,13 @@ impl From for FormattingError { } } +impl From for FormattingError { + #[inline] + fn from(error: alloc::Error) -> Self { + FormattingError::AllocError(error) + } +} + impl crate::no_std::error::Error for FormattingError { fn source(&self) -> Option<&(dyn crate::no_std::error::Error + 'static)> { match self { diff --git a/crates/rune/src/fmt/indent_writer.rs b/crates/rune/src/fmt/indent_writer.rs index f70c882c2..fb780cd51 100644 --- a/crates/rune/src/fmt/indent_writer.rs +++ b/crates/rune/src/fmt/indent_writer.rs @@ -6,9 +6,9 @@ mod tests; use core::ops::{Deref, DerefMut}; use core::str; -use crate::no_std::io::{self, Write}; -use crate::no_std::prelude::*; - +use crate::alloc::fmt::TryWrite; +use crate::alloc::prelude::*; +use crate::alloc::{self, try_vec, Vec}; use crate::ast::Span; use super::comments::Comment; @@ -22,12 +22,12 @@ pub(super) struct IndentedWriter { } impl IndentedWriter { - pub(super) fn new() -> Self { - Self { - lines: vec![Vec::new()], + pub(super) fn new() -> alloc::Result { + Ok(Self { + lines: try_vec![Vec::new()], indent: 0, needs_indent: true, - } + }) } pub(super) fn into_inner(self) -> Vec> { @@ -42,10 +42,10 @@ impl IndentedWriter { self.indent = self.indent.saturating_sub(4); } - fn write_indent(&mut self) -> io::Result { + fn write_indent(&mut self) -> alloc::Result { for _ in 0..self.indent { if let Some(line) = self.lines.last_mut() { - line.push(b' '); + line.try_push(b' ')?; } } @@ -53,16 +53,18 @@ impl IndentedWriter { } } -impl Write for IndentedWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - if buf[0] == b'\n' { +impl TryWrite for IndentedWriter { + fn try_write_str(&mut self, buf: &str) -> alloc::Result<()> { + if buf.starts_with('\n') { self.needs_indent = true; - self.lines.push(Vec::new()); - return Ok(buf.len()); + self.lines.try_push(Vec::new())?; + return Ok(()); } - let ends_with_newline = buf.last() == Some(&b'\n'); - let line_count = buf.iter().filter(|&&b| b == b'\n').count(); - let lines = buf.split(|&b| b == b'\n'); + + let ends_with_newline = buf.ends_with('\n'); + let line_count = buf.chars().filter(|&b| b == '\n').count(); + let lines = buf.split(|b| b == '\n'); + let lines_to_write = if ends_with_newline { line_count } else { @@ -77,20 +79,16 @@ impl Write for IndentedWriter { if !line.is_empty() { if let Some(last_line) = self.lines.last_mut() { - last_line.extend(line); + last_line.try_extend_from_slice(line.as_bytes())?; } } if idx < line_count.saturating_sub(1) || ends_with_newline { - self.lines.push(Vec::new()); + self.lines.try_push(Vec::new())?; self.needs_indent = true; } } - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -123,10 +121,11 @@ impl<'a> SpanInjectionWriter<'a> { let empty_line_spans = super::whitespace::gather_empty_line_spans(source)?; let mut queued_spans = Vec::new(); - queued_spans.extend(comment_spans.into_iter().map(ResolvedSpan::Comment)); - queued_spans.extend(empty_line_spans.into_iter().map(ResolvedSpan::Empty)); + queued_spans.try_extend(comment_spans.into_iter().map(ResolvedSpan::Comment))?; + queued_spans.try_extend(empty_line_spans.into_iter().map(ResolvedSpan::Empty))?; queued_spans.sort_by_key(|span| span.span().start); + Ok(Self { writer, queued_spans, @@ -145,8 +144,8 @@ impl<'a> SpanInjectionWriter<'a> { if comment.on_new_line { writeln!(self.writer, "{}", self.resolve(comment.span)?)?; } else { - self.extend_previous_line(b" "); - self.extend_previous_line(self.resolve(comment.span)?.as_bytes()); + self.extend_previous_line(b" ")?; + self.extend_previous_line(self.resolve(comment.span)?.as_bytes())?; } } } @@ -155,18 +154,19 @@ impl<'a> SpanInjectionWriter<'a> { Ok(self.writer.into_inner()) } - fn extend_previous_line(&mut self, text: &[u8]) { + fn extend_previous_line(&mut self, text: &[u8]) -> alloc::Result<()> { let Some(idx) = self.writer.lines.len().checked_sub(2) else { // TODO: bubble up an internal error? - return; + return Ok(()); }; let Some(last_line) = self.writer.lines.get_mut(idx) else { // TODO: bubble up an internal error? - return; + return Ok(()); }; - last_line.extend(text); + last_line.try_extend_from_slice(text)?; + Ok(()) } fn resolve(&self, span: Span) -> Result<&'a str, FormattingError> { @@ -223,8 +223,8 @@ impl<'a> SpanInjectionWriter<'a> { if comment.on_new_line { writeln!(self.writer, "{}", self.resolve(comment.span)?)?; } else { - self.extend_previous_line(b" "); - self.extend_previous_line(self.resolve(comment.span)?.as_bytes()); + self.extend_previous_line(b" ")?; + self.extend_previous_line(self.resolve(comment.span)?.as_bytes())?; } } } diff --git a/crates/rune/src/fmt/indent_writer/tests.rs b/crates/rune/src/fmt/indent_writer/tests.rs index 222152cf8..2be542bf7 100644 --- a/crates/rune/src/fmt/indent_writer/tests.rs +++ b/crates/rune/src/fmt/indent_writer/tests.rs @@ -1,22 +1,27 @@ -use super::*; +use crate::alloc::fmt::TryWrite; +use crate::support::Result; + +use super::IndentedWriter; #[test] -fn test_roundtrip() { - let mut writer = IndentedWriter::new(); - writer.write_all(b"hello\nworld\n").unwrap(); +fn test_roundtrip() -> Result<()> { + let mut writer = IndentedWriter::new()?; + writer.try_write_str("hello\nworld\n")?; assert_eq!( writer.into_inner(), [&b"hello"[..], &b"world"[..], &b""[..]] ); + Ok(()) } #[test] -fn test_roundtrip_with_indent() { - let mut writer = IndentedWriter::new(); +fn test_roundtrip_with_indent() -> Result<()> { + let mut writer = IndentedWriter::new()?; writer.indent(); - writer.write_all(b"hello\nworld\n").unwrap(); + writer.try_write_str("hello\nworld\n")?; assert_eq!( writer.into_inner(), [&b" hello"[..], &b" world"[..], &b""[..]] ); + Ok(()) } diff --git a/crates/rune/src/fmt/printer.rs b/crates/rune/src/fmt/printer.rs index 11338ac33..d3621026e 100644 --- a/crates/rune/src/fmt/printer.rs +++ b/crates/rune/src/fmt/printer.rs @@ -2,9 +2,9 @@ use core::mem::take; -use crate::no_std::io::Write; -use crate::no_std::prelude::*; - +use crate::alloc::fmt::TryWrite; +use crate::alloc::prelude::*; +use crate::alloc::Vec; use crate::ast::{self, Span, Spanned}; use super::error::FormattingError; @@ -20,7 +20,7 @@ pub(super) struct Printer<'a> { impl<'a> Printer<'a> { pub(super) fn new(source: &'a str) -> Result { - let writer = SpanInjectionWriter::new(IndentedWriter::new(), source)?; + let writer = SpanInjectionWriter::new(IndentedWriter::new()?, source)?; Ok(Self { writer, source }) } @@ -39,15 +39,15 @@ impl<'a> Printer<'a> { } if !take(&mut head) { - out.resize(out.len().saturating_add(lines), b'\n'); + out.try_resize(out.len().saturating_add(lines), b'\n')?; } - out.extend(line); + out.try_extend(line)?; lines = 1; } if lines > 0 { - out.push(b'\n'); + out.try_push(b'\n')?; } Ok(out) diff --git a/crates/rune/src/fmt/tests.rs b/crates/rune/src/fmt/tests.rs index ac7c97983..92b0f02db 100644 --- a/crates/rune/src/fmt/tests.rs +++ b/crates/rune/src/fmt/tests.rs @@ -1,13 +1,14 @@ -use crate::no_std::prelude::*; - +use crate::alloc::prelude::*; +use crate::alloc::{String, Vec}; use crate::fmt::FormattingError; +use crate::support::Result; pub(crate) fn layout_string(contents: String) -> Result, FormattingError> { super::layout_source(&contents) } #[test] -fn test_layout_string() { +fn test_layout_string() -> Result<()> { let input = r#" fn main() { let x = 1; let y = 2; x + y @@ -21,14 +22,13 @@ fn test_layout_string() { } "#; - assert_eq!( - layout_string(input.to_owned()).unwrap(), - expected.as_bytes() - ); + assert_eq!(layout_string(input.try_to_owned()?)?, expected.as_bytes()); + + Ok(()) } #[test] -fn test_layout_two_fns() { +fn test_layout_two_fns() -> Result<()> { let input = r#" fn main() { let x = 1; let y = 2; x + y @@ -52,14 +52,13 @@ fn foo() { } "#; - assert_eq!( - layout_string(input.to_owned()).unwrap(), - expected.as_bytes() - ); + assert_eq!(layout_string(input.try_to_owned()?)?, expected.as_bytes()); + + Ok(()) } #[test] -fn test_layout_two_fns_with_comments() { +fn test_layout_two_fns_with_comments() -> Result<()> { let input = r#" fn main() { let x = 1; let y = 2; x + y @@ -85,14 +84,13 @@ fn foo() { } "#; - assert_eq!( - layout_string(input.to_owned()).unwrap(), - expected.as_bytes() - ); + assert_eq!(layout_string(input.try_to_owned()?)?, expected.as_bytes()); + + Ok(()) } #[test] -fn test_macrocall_whitespace() { +fn test_macrocall_whitespace() -> Result<()> { let input = r#" fn main() { foo!(); @@ -108,13 +106,14 @@ fn test_macrocall_whitespace() { } "#; - let output = layout_string(input.to_owned()).unwrap(); - let output = layout_string(String::from_utf8(output).unwrap()).unwrap(); - assert_eq!(std::str::from_utf8(&output).unwrap(), expected); + let output = layout_string(input.try_to_owned()?)?; + let output = layout_string(String::from_utf8(output)?)?; + assert_eq!(std::str::from_utf8(&output)?, expected); + Ok(()) } #[test] -fn test_macrocall_whitespace2() { +fn test_macrocall_whitespace2() -> Result<()> { let input = r#"make_function!(root_fn => { "Hello World!" }); // NB: we put the import in the bottom to test that import resolution isn't order-dependent. "#; @@ -123,16 +122,17 @@ fn test_macrocall_whitespace2() { // NB: we put the import in the bottom to test that import resolution isn't order-dependent. "#; - let output = layout_string(input.to_owned()).unwrap(); - assert_eq!(std::str::from_utf8(&output).unwrap(), expected); - let output = layout_string(String::from_utf8(output).unwrap()).unwrap(); - assert_eq!(std::str::from_utf8(&output).unwrap(), expected); - let output = layout_string(String::from_utf8(output).unwrap()).unwrap(); - assert_eq!(std::str::from_utf8(&output).unwrap(), expected); + let output = layout_string(input.try_to_owned()?)?; + assert_eq!(std::str::from_utf8(&output)?, expected); + let output = layout_string(String::from_utf8(output)?)?; + assert_eq!(std::str::from_utf8(&output)?, expected); + let output = layout_string(String::from_utf8(output)?)?; + assert_eq!(std::str::from_utf8(&output)?, expected); + Ok(()) } #[test] -fn test_macrocall_whitespace3() { +fn test_macrocall_whitespace3() -> Result<()> { let input = r#"make_function!(root_fn => { "Hello World!" }); @@ -149,10 +149,11 @@ fn test_macrocall_whitespace3() { // NB: we put the import in the bottom to test that import resolution isn't order-dependent. "#; - let output = layout_string(input.to_owned()).unwrap(); - assert_eq!(std::str::from_utf8(&output).unwrap(), expected); - let output = layout_string(String::from_utf8(output).unwrap()).unwrap(); - assert_eq!(std::str::from_utf8(&output).unwrap(), expected); - let output = layout_string(String::from_utf8(output).unwrap()).unwrap(); - assert_eq!(std::str::from_utf8(&output).unwrap(), expected); + let output = layout_string(input.try_to_owned()?)?; + assert_eq!(std::str::from_utf8(&output)?, expected); + let output = layout_string(String::from_utf8(output)?)?; + assert_eq!(std::str::from_utf8(&output)?, expected); + let output = layout_string(String::from_utf8(output)?)?; + assert_eq!(std::str::from_utf8(&output)?, expected); + Ok(()) } diff --git a/crates/rune/src/hash.rs b/crates/rune/src/hash.rs index d90289a9a..d414c5e35 100644 --- a/crates/rune/src/hash.rs +++ b/crates/rune/src/hash.rs @@ -1,4 +1,4 @@ -use crate::no_std::collections::HashMap; +use crate::alloc::HashMap; use core::hash::{BuildHasher, Hasher}; diff --git a/crates/rune/src/hashbrown/table.rs b/crates/rune/src/hashbrown/table.rs index 744e2229f..6a2e62c84 100644 --- a/crates/rune/src/hashbrown/table.rs +++ b/crates/rune/src/hashbrown/table.rs @@ -6,7 +6,8 @@ use core::marker::PhantomData; use core::mem; use core::ptr; -use crate::alloc::{Allocator, Error, Global, TryClone}; +use crate::alloc; +use crate::alloc::prelude::*; #[cfg(feature = "alloc")] use crate::runtime::Hasher; @@ -15,24 +16,24 @@ use crate::runtime::{ProtocolCaller, RawRef, Ref, Value, VmError, VmResult}; use crate::alloc::hashbrown::raw::{RawIter, RawTable}; use crate::alloc::hashbrown::ErrorOrInsertSlot; -pub(crate) struct Table { - table: RawTable<(Value, V), A>, +pub(crate) struct Table { + table: RawTable<(Value, V)>, state: hash_map::RandomState, } -impl Table { +impl Table { #[inline(always)] - pub(crate) fn new_in(alloc: A) -> Self { + pub(crate) fn new() -> Self { Self { - table: RawTable::new_in(alloc), + table: RawTable::new(), state: hash_map::RandomState::new(), } } #[inline(always)] - pub(crate) fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + pub(crate) fn try_with_capacity(capacity: usize) -> alloc::Result { Ok(Self { - table: RawTable::try_with_capacity_in(capacity, alloc)?, + table: RawTable::try_with_capacity(capacity)?, state: hash_map::RandomState::new(), }) } @@ -155,11 +156,11 @@ impl Table { } } -impl TryClone for Table +impl TryClone for Table where V: TryClone, { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { table: self.table.try_clone()?, state: self.state.clone(), @@ -167,7 +168,7 @@ where } #[inline] - fn try_clone_from(&mut self, source: &Self) -> Result<(), Error> { + fn try_clone_from(&mut self, source: &Self) -> alloc::Result<()> { self.table.try_clone_from(&source.table) } } diff --git a/crates/rune/src/hir/arena.rs b/crates/rune/src/hir/arena.rs index 8c32dfd59..e9ca3b0cb 100644 --- a/crates/rune/src/hir/arena.rs +++ b/crates/rune/src/hir/arena.rs @@ -9,7 +9,7 @@ use core::ptr; use core::slice; use core::str; -use crate::no_std::collections::HashMap; +use crate::alloc::{self, HashMap}; use crate::no_std::prelude::*; #[non_exhaustive] @@ -23,6 +23,12 @@ pub struct ArenaAllocError { pub requested: usize, } +impl From for ArenaAllocError { + fn from(_: alloc::Error) -> Self { + Self { requested: 0 } + } +} + /// The size of a slab in the arena allocator. const PAGE: usize = 4096; const HUGE_PAGE: usize = 2 * 1024 * 1024; @@ -84,7 +90,7 @@ impl Arena { slice::from_raw_parts(ptr.as_ptr() as *const _, bytes.len()) }; - self.bytes.borrow_mut().insert(bytes.into(), ptr); + self.bytes.borrow_mut().try_insert(bytes.into(), ptr)?; Ok(output) } diff --git a/crates/rune/src/hir/hir.rs b/crates/rune/src/hir/hir.rs index 17e27eec6..3e3320444 100644 --- a/crates/rune/src/hir/hir.rs +++ b/crates/rune/src/hir/hir.rs @@ -1,9 +1,9 @@ use core::fmt; use core::num::NonZeroUsize; -use crate::no_std::prelude::*; - use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, String}; use crate::ast::{self, Span, Spanned}; use crate::compile::{ItemId, ModId}; use crate::parse::NonZeroId; @@ -11,7 +11,7 @@ use crate::runtime::{format, Type, TypeCheck}; use crate::Hash; /// An owned name. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) enum OwnedName { SelfValue, Str(String), @@ -40,7 +40,8 @@ impl fmt::Display for OwnedName { } /// A captured variable. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] pub(crate) enum Name<'hir> { /// Capture of the `self` value. SelfValue, @@ -52,12 +53,12 @@ pub(crate) enum Name<'hir> { impl<'hir> Name<'hir> { /// Coerce into an owned name. - pub(crate) fn into_owned(self) -> OwnedName { - match self { + pub(crate) fn into_owned(self) -> alloc::Result { + Ok(match self { Name::SelfValue => OwnedName::SelfValue, - Name::Str(name) => OwnedName::Str(name.to_owned()), + Name::Str(name) => OwnedName::Str(name.try_to_owned()?), Name::Id(id) => OwnedName::Id(id), - } + }) } /// Test if the name starts with the given test. @@ -81,7 +82,8 @@ impl fmt::Display for Name<'_> { } /// A pattern. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct Pat<'hir> { /// The span of the pattern. @@ -91,14 +93,16 @@ pub(crate) struct Pat<'hir> { pub(crate) kind: PatKind<'hir>, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) enum PatPathKind<'hir> { Kind(&'hir PatSequenceKind), Ident(&'hir str), } /// The kind of a [Pat]. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) enum PatKind<'hir> { /// An ignored binding. Ignore, @@ -112,7 +116,8 @@ pub(crate) enum PatKind<'hir> { Object(&'hir PatObject<'hir>), } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) enum PatSequenceKind { Type { hash: Hash, @@ -133,7 +138,8 @@ pub(crate) enum PatSequenceKind { } /// Items pattern matching. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct PatSequence<'hir> { /// The kind of pattern items. @@ -143,7 +149,8 @@ pub(crate) struct PatSequence<'hir> { } /// Object pattern matching. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct PatObject<'hir> { /// The kind of pattern items. @@ -152,7 +159,8 @@ pub(crate) struct PatObject<'hir> { pub(crate) bindings: &'hir [Binding<'hir>], } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) enum Binding<'hir> { Binding(Span, &'hir str, &'hir Pat<'hir>), @@ -178,7 +186,8 @@ impl<'hir> Binding<'hir> { } /// An expression. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct Expr<'hir> { /// Span of the expression. @@ -189,7 +198,8 @@ pub(crate) struct Expr<'hir> { } /// The kind of a number. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) enum Lit<'hir> { Bool(bool), @@ -202,7 +212,8 @@ pub(crate) enum Lit<'hir> { } /// The kind of an [Expr]. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) enum ExprKind<'hir> { Variable(Name<'hir>), @@ -242,7 +253,8 @@ pub(crate) enum ExprKind<'hir> { } /// An internally resolved template. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] pub(crate) struct BuiltInTemplate<'hir> { /// The span of the built-in template. #[rune(span)] @@ -254,7 +266,8 @@ pub(crate) struct BuiltInTemplate<'hir> { } /// An internal format specification. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] pub(crate) struct BuiltInFormat<'hir> { #[rune(span)] pub(crate) span: Span, @@ -275,7 +288,8 @@ pub(crate) struct BuiltInFormat<'hir> { } /// An assign expression `a = b`. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprAssign<'hir> { /// The expression being assigned to. @@ -285,7 +299,8 @@ pub(crate) struct ExprAssign<'hir> { } /// A `loop` expression: `loop { ... }`. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprLoop<'hir> { /// A label. @@ -300,7 +315,8 @@ pub(crate) struct ExprLoop<'hir> { } /// A `for` loop over an iterator: `for i in [1, 2, 3] {}`. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprFor<'hir> { /// The label of the loop. @@ -318,7 +334,8 @@ pub(crate) struct ExprFor<'hir> { } /// A let expression `let = ` -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprLet<'hir> { /// The name of the binding. @@ -334,7 +351,8 @@ pub(crate) struct ExprLet<'hir> { /// ```text /// if cond { true } else { false } /// ``` -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct Conditional<'hir> { /// Else if branches. @@ -342,7 +360,8 @@ pub(crate) struct Conditional<'hir> { } /// An else branch of an if expression. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ConditionalBranch<'hir> { /// Span of the expression. @@ -359,7 +378,8 @@ pub(crate) struct ConditionalBranch<'hir> { } /// A match expression. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprMatch<'hir> { /// The expression who's result we match over. @@ -369,7 +389,8 @@ pub(crate) struct ExprMatch<'hir> { } /// A match branch. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprMatchBranch<'hir> { /// Span of the expression. @@ -387,7 +408,8 @@ pub(crate) struct ExprMatchBranch<'hir> { pub(crate) drop: &'hir [Name<'hir>], } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) enum Call<'hir> { Var { /// The name of the variable being called. @@ -417,7 +439,8 @@ pub(crate) enum Call<'hir> { } /// A function call `()`. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprCall<'hir> { /// The call being performed. @@ -427,7 +450,8 @@ pub(crate) struct ExprCall<'hir> { } /// A field access `.`. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprFieldAccess<'hir> { /// The expr where the field is being accessed. @@ -437,7 +461,8 @@ pub(crate) struct ExprFieldAccess<'hir> { } /// The field being accessed. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) enum ExprField<'hir> { /// A tuple index. @@ -461,7 +486,8 @@ pub(crate) enum ExprField<'hir> { } /// A binary expression. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprBinary<'hir> { /// The left-hand side of a binary operation. @@ -473,7 +499,8 @@ pub(crate) struct ExprBinary<'hir> { } /// A unary expression. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprUnary<'hir> { /// The operation to apply. @@ -483,7 +510,8 @@ pub(crate) struct ExprUnary<'hir> { } /// An index get operation `[]`. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprIndex<'hir> { /// The target of the index set. @@ -493,7 +521,8 @@ pub(crate) struct ExprIndex<'hir> { } /// An async block being called. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprAsyncBlock<'hir> { pub(crate) hash: Hash, @@ -501,7 +530,8 @@ pub(crate) struct ExprAsyncBlock<'hir> { pub(crate) captures: &'hir [Name<'hir>], } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) struct ExprBreak<'hir> { /// Label being continued. pub(crate) label: Option<&'hir str>, @@ -512,7 +542,8 @@ pub(crate) struct ExprBreak<'hir> { pub(crate) drop: &'hir [Name<'hir>], } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) struct ExprContinue<'hir> { /// Label being continued. pub(crate) label: Option<&'hir str>, @@ -522,7 +553,8 @@ pub(crate) struct ExprContinue<'hir> { } /// A `select` expression that selects over a collection of futures. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprSelect<'hir> { /// The branches of the select. @@ -530,7 +562,8 @@ pub(crate) struct ExprSelect<'hir> { } /// A single selection branch. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) enum ExprSelectBranch<'hir> { /// A patterned branch. @@ -540,7 +573,8 @@ pub(crate) enum ExprSelectBranch<'hir> { } /// A single selection branch. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprSelectPatBranch<'hir> { /// The identifier to bind the result to. @@ -555,7 +589,8 @@ pub(crate) struct ExprSelectPatBranch<'hir> { } /// Calling a closure. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprCallClosure<'hir> { pub(crate) do_move: bool, @@ -564,7 +599,8 @@ pub(crate) struct ExprCallClosure<'hir> { } /// A closure expression. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprClosure<'hir> { /// Arguments to the closure. @@ -575,7 +611,8 @@ pub(crate) struct ExprClosure<'hir> { pub(crate) captures: &'hir [Name<'hir>], } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) enum ExprObjectKind { EmptyStruct { hash: Hash }, Struct { hash: Hash }, @@ -585,7 +622,8 @@ pub(crate) enum ExprObjectKind { } /// An object expression. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprObject<'hir> { /// The kind of an object being created. @@ -595,7 +633,8 @@ pub(crate) struct ExprObject<'hir> { } /// A single field assignment in an object expression. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct FieldAssign<'hir> { /// The key of the field. @@ -607,7 +646,8 @@ pub(crate) struct FieldAssign<'hir> { } /// A literal vector. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ExprSeq<'hir> { /// Items in the vector. @@ -615,7 +655,8 @@ pub(crate) struct ExprSeq<'hir> { } /// A range expression such as `a .. b` or `a ..= b`. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) enum ExprRange<'hir> { /// `start..`. @@ -633,7 +674,8 @@ pub(crate) enum ExprRange<'hir> { } /// The condition in an if statement. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) enum Condition<'hir> { /// A regular expression. @@ -642,7 +684,8 @@ pub(crate) enum Condition<'hir> { ExprLet(&'hir ExprLet<'hir>), } -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct ItemFn<'hir> { /// The span of the function. @@ -655,7 +698,8 @@ pub(crate) struct ItemFn<'hir> { } /// A single argument to a function. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) enum FnArg<'hir> { /// The `self` parameter. @@ -665,7 +709,8 @@ pub(crate) enum FnArg<'hir> { } /// A block of statements. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct Block<'hir> { /// The span of the block. @@ -687,14 +732,16 @@ impl Block<'_> { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) struct AsyncBlock<'hir> { pub(crate) block: Block<'hir>, pub(crate) captures: &'hir [Name<'hir>], } /// A statement within a block. -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) enum Stmt<'hir> { /// A local declaration. @@ -708,7 +755,8 @@ pub(crate) enum Stmt<'hir> { } /// A local variable declaration `let = ;` -#[derive(Debug, Clone, Copy, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, Spanned)] +#[try_clone(copy)] #[non_exhaustive] pub(crate) struct Local<'hir> { /// The span of the local declaration. diff --git a/crates/rune/src/hir/interpreter.rs b/crates/rune/src/hir/interpreter.rs index 521117181..ecc20c3fb 100644 --- a/crates/rune/src/hir/interpreter.rs +++ b/crates/rune/src/hir/interpreter.rs @@ -1,5 +1,4 @@ -use crate::no_std::collections::HashMap; - +use crate::alloc::HashMap; use crate::runtime::Value; /// HIR interpreter. diff --git a/crates/rune/src/hir/lowering.rs b/crates/rune/src/hir/lowering.rs index 99bc4935f..78b7dd9d2 100644 --- a/crates/rune/src/hir/lowering.rs +++ b/crates/rune/src/hir/lowering.rs @@ -1,11 +1,11 @@ use core::cell::Cell; use core::ops::Neg; -use crate::no_std::collections::{HashMap, HashSet}; -use crate::no_std::prelude::*; - use num::ToPrimitive; +use crate::alloc::prelude::*; +use crate::alloc::try_format; +use crate::alloc::{self, Box, HashMap, HashSet}; use crate::ast::{self, Spanned}; use crate::compile::meta; use crate::compile::{self, DynLocation, ErrorKind, Item, ItemId, WithSpan}; @@ -56,7 +56,7 @@ impl<'hir, 'a, 'arena> Ctxt<'hir, 'a, 'arena> { arena: &'hir hir::arena::Arena, q: Query<'a, 'arena>, source_id: SourceId, - ) -> Self { + ) -> alloc::Result { Self::inner(arena, q, source_id, false) } @@ -66,7 +66,7 @@ impl<'hir, 'a, 'arena> Ctxt<'hir, 'a, 'arena> { arena: &'hir hir::arena::Arena, q: Query<'a, 'arena>, source_id: SourceId, - ) -> Self { + ) -> alloc::Result { Self::inner(arena, q, source_id, true) } @@ -75,17 +75,17 @@ impl<'hir, 'a, 'arena> Ctxt<'hir, 'a, 'arena> { q: Query<'a, 'arena>, source_id: SourceId, const_eval: bool, - ) -> Self { - Self { + ) -> alloc::Result { + Ok(Self { arena, q, source_id, in_template: Cell::new(false), in_path: Cell::new(false), needs: Cell::new(Needs::default()), - scopes: hir::Scopes::default(), + scopes: hir::Scopes::new()?, const_eval, - } + }) } #[allow(unused)] @@ -168,18 +168,18 @@ pub(crate) fn async_block_secondary<'hir>( let Some(captures) = cx.q.get_captures(captures) else { return Err(compile::Error::msg( ast, - format_args!("Missing captures for hash {captures}"), + try_format!("Missing captures for hash {captures}"), )); }; let captures = &*iter!(captures, |capture| { match capture { - hir::OwnedName::SelfValue => cx.scopes.define(hir::Name::SelfValue).with_span(ast)?, + hir::OwnedName::SelfValue => cx.scopes.define(hir::Name::SelfValue, ast)?, hir::OwnedName::Str(name) => { let name = alloc_str!(name.as_str()); - cx.scopes.define(hir::Name::Str(name)).with_span(ast)? + cx.scopes.define(hir::Name::Str(name), ast)? } - hir::OwnedName::Id(id) => cx.scopes.define(hir::Name::Id(*id)).with_span(ast)?, + hir::OwnedName::Id(id) => cx.scopes.define(hir::Name::Id(*id), ast)?, } }); @@ -203,20 +203,20 @@ pub(crate) fn expr_closure_secondary<'hir>( let Some(captures) = cx.q.get_captures(captures) else { return Err(compile::Error::msg( ast, - format_args!("Missing captures for hash {captures}"), + try_format!("Missing captures for hash {captures}"), )); }; let captures = &*iter!(captures, |capture| match capture { hir::OwnedName::SelfValue => { - cx.scopes.define(hir::Name::SelfValue).with_span(ast)? + cx.scopes.define(hir::Name::SelfValue, ast)? } hir::OwnedName::Str(name) => { let name = hir::Name::Str(alloc_str!(name.as_str())); - cx.scopes.define(name).with_span(ast)? + cx.scopes.define(name, ast)? } hir::OwnedName::Id(id) => { - cx.scopes.define(hir::Name::Id(*id)).with_span(ast)? + cx.scopes.define(hir::Name::Id(*id), ast)? } }); @@ -244,7 +244,7 @@ fn expr_call_closure<'hir>( return Err(compile::Error::new( ast, ErrorKind::MissingItem { - item: cx.q.pool.item(item.item).to_owned(), + item: cx.q.pool.item(item.item).try_to_owned()?, }, )); }; @@ -252,7 +252,7 @@ fn expr_call_closure<'hir>( let meta::Kind::Closure { call, do_move, .. } = meta.kind else { return Err(compile::Error::expected_meta( ast, - meta.info(cx.q.pool), + meta.info(cx.q.pool)?, "a closure", )); }; @@ -270,16 +270,16 @@ fn expr_call_closure<'hir>( expr(cx, &ast.body)?; let layer = cx.scopes.pop().with_span(&ast.body)?; - cx.q.set_used(&meta.item_meta); - cx.q.inner.queue.push_back(BuildEntry { + cx.q.set_used(&meta.item_meta)?; + cx.q.inner.queue.try_push_back(BuildEntry { item_meta: meta.item_meta, build: Build::Closure(indexing::Closure { - ast: Box::new(ast.clone()), + ast: Box::try_new(ast.try_clone()?)?, call, }), - }); + })?; - cx.q.insert_captures(meta.hash, layer.captures()); + cx.q.insert_captures(meta.hash, layer.captures())?; iter!(layer.captures()) } Some(captures) => { @@ -372,7 +372,7 @@ pub(crate) fn expr_object<'hir>( let assignments = &mut *iter!(&ast.assignments, |(ast, _)| { let key = object_key(cx, &ast.key)?; - if let Some(_existing) = keys_dup.insert(key.1, key.0) { + if let Some(_existing) = keys_dup.try_insert(key.1, key.0)? { return Err(compile::Error::new( key.0, ErrorKind::DuplicateObjectKey { @@ -387,11 +387,11 @@ pub(crate) fn expr_object<'hir>( let assign = match &ast.assign { Some((_, ast)) => expr(cx, ast)?, None => { - let Some((name, _)) = cx.scopes.get(hir::Name::Str(key.1)) else { + let Some((name, _)) = cx.scopes.get(hir::Name::Str(key.1))? else { return Err(compile::Error::new( key.0, ErrorKind::MissingLocal { - name: key.1.to_owned(), + name: key.1.try_to_string()?.try_into()?, }, )); }; @@ -411,7 +411,7 @@ pub(crate) fn expr_object<'hir>( }); let mut check_object_fields = |fields: &HashMap<_, meta::FieldMeta>, item: &Item| { - let mut fields = fields.clone(); + let mut fields = fields.try_clone()?; for assign in assignments.iter_mut() { match fields.remove(assign.key.1) { @@ -422,8 +422,8 @@ pub(crate) fn expr_object<'hir>( return Err(compile::Error::new( assign.key.0, ErrorKind::LitObjectNotField { - field: assign.key.1.into(), - item: item.to_owned(), + field: assign.key.1.try_into()?, + item: item.try_to_owned()?, }, )); } @@ -435,7 +435,7 @@ pub(crate) fn expr_object<'hir>( span, ErrorKind::LitObjectMissingField { field, - item: item.to_owned(), + item: item.try_to_owned()?, }, )); } @@ -484,7 +484,7 @@ pub(crate) fn expr_object<'hir>( return Err(compile::Error::new( span, ErrorKind::UnsupportedLitObject { - meta: meta.info(cx.q.pool), + meta: meta.info(cx.q.pool)?, }, )); } @@ -923,16 +923,16 @@ pub(crate) fn expr_block<'hir>( block(cx, &ast.block)?; let layer = cx.scopes.pop().with_span(&ast.block)?; - cx.q.insert_captures(meta.hash, layer.captures()); + cx.q.insert_captures(meta.hash, layer.captures())?; - cx.q.set_used(&meta.item_meta); - cx.q.inner.queue.push_back(BuildEntry { + cx.q.set_used(&meta.item_meta)?; + cx.q.inner.queue.try_push_back(BuildEntry { item_meta: meta.item_meta, build: Build::AsyncBlock(indexing::AsyncBlock { - ast: ast.block.clone(), + ast: ast.block.try_clone()?, call, }), - }); + })?; iter!(layer.captures()) } @@ -954,7 +954,7 @@ pub(crate) fn expr_block<'hir>( (ExprBlockKind::Const, meta::Kind::Const { .. }) => Ok(hir::ExprKind::Const(meta.hash)), _ => Err(compile::Error::expected_meta( ast, - meta.info(cx.q.pool), + meta.info(cx.q.pool)?, "async or const block", )), } @@ -978,7 +978,7 @@ fn expr_break<'hir>( return Err(compile::Error::new( ast, ErrorKind::MissingLoopLabel { - label: label.into(), + label: label.try_into()?, }, )); } else { @@ -1017,7 +1017,7 @@ fn expr_continue<'hir>( return Err(compile::Error::new( ast, ErrorKind::MissingLoopLabel { - label: label.into(), + label: label.try_into()?, }, )); } else { @@ -1043,7 +1043,7 @@ fn fn_arg<'hir>( Ok(match ast { ast::FnArg::SelfValue(ast) => { - cx.scopes.define(hir::Name::SelfValue).with_span(ast)?; + cx.scopes.define(hir::Name::SelfValue, ast)?; hir::FnArg::SelfValue(ast.span()) } ast::FnArg::Pat(ast) => hir::FnArg::Pat(alloc!(pat(cx, ast)?)), @@ -1102,7 +1102,7 @@ fn pat<'hir>(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Pat) -> compile::Result(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Pat) -> compile::Result(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Pat) -> compile::Result { @@ -1208,7 +1208,7 @@ fn pat<'hir>(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Pat) -> compile::Result(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Pat) -> compile::Result(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Pat) -> compile::Result::from) - .collect::>(); + let mut fields = fields.into_iter().try_collect::>()?; fields.sort(); return Err(compile::Error::new( ast, ErrorKind::PatternMissingFields { - item: cx.q.pool.item(meta.item_meta.item).to_owned(), + item: cx.q.pool.item(meta.item_meta.item).try_to_owned()?, #[cfg(feature = "emit")] fields, }, @@ -1323,7 +1320,7 @@ pub(crate) fn expr_path<'hir>( alloc_with!(cx, ast); if let Some(ast::PathKind::SelfValue) = ast.as_kind() { - let Some(..) = cx.scopes.get(hir::Name::SelfValue) else { + let Some(..) = cx.scopes.get(hir::Name::SelfValue)? else { return Err(compile::Error::new(ast, ErrorKind::MissingSelf)); }; @@ -1334,7 +1331,7 @@ pub(crate) fn expr_path<'hir>( if let Some(name) = ast.try_as_ident() { let name = alloc_str!(name.resolve(resolve_context!(cx.q))?); - if let Some((name, _)) = cx.scopes.get(hir::Name::Str(name)) { + if let Some((name, _)) = cx.scopes.get(hir::Name::Str(name))? { return Ok(hir::ExprKind::Variable(name)); } } @@ -1362,7 +1359,7 @@ pub(crate) fn expr_path<'hir>( return Err(compile::Error::new( ast, ErrorKind::MissingLocal { - name: local.to_owned(), + name: Box::::try_from(local)?, }, )); } @@ -1370,12 +1367,12 @@ pub(crate) fn expr_path<'hir>( let kind = if !parameters.parameters.is_empty() { ErrorKind::MissingItemParameters { - item: cx.q.pool.item(named.item).to_owned(), - parameters: parameters.parameters.as_ref().into(), + item: cx.q.pool.item(named.item).try_to_owned()?, + parameters: parameters.parameters.into_iter().try_collect()?, } } else { ErrorKind::MissingItem { - item: cx.q.pool.item(named.item).to_owned(), + item: cx.q.pool.item(named.item).try_to_owned()?, } }; @@ -1430,14 +1427,18 @@ fn expr_path_meta<'hir>( } _ => Err(compile::Error::expected_meta( span, - meta.info(cx.q.pool), + meta.info(cx.q.pool)?, "something that can be used as a value", )), } } else { - let type_hash = meta.type_hash_of().ok_or_else(|| { - compile::Error::expected_meta(span, meta.info(cx.q.pool), "something that has a type") - })?; + let Some(type_hash) = meta.type_hash_of() else { + return Err(compile::Error::expected_meta( + span, + meta.info(cx.q.pool)?, + "something that has a type", + )); + }; Ok(hir::ExprKind::Type(Type::new(type_hash))) } @@ -1489,7 +1490,7 @@ fn struct_match_for( cx: &Ctxt<'_, '_, '_>, meta: &meta::Meta, open: bool, -) -> Option<(HashSet>, hir::PatSequenceKind)> { +) -> alloc::Result>, hir::PatSequenceKind)>> { let (fields, kind) = match &meta.kind { meta::Kind::Struct { fields, .. } => { (fields, hir::PatSequenceKind::Type { hash: meta.hash }) @@ -1513,18 +1514,22 @@ fn struct_match_for( (fields, kind) } _ => { - return None; + return Ok(None); } }; let fields = match fields { meta::Fields::Unnamed(0) if open => HashSet::new(), meta::Fields::Empty if open => HashSet::new(), - meta::Fields::Named(st) => st.fields.keys().cloned().collect(), - _ => return None, + meta::Fields::Named(st) => st + .fields + .keys() + .try_cloned() + .try_collect::>()??, + _ => return Ok(None), }; - Some((fields, kind)) + Ok(Some((fields, kind))) } fn tuple_match_for( @@ -1701,7 +1706,7 @@ fn expr_call<'hir>( _ => { return Err(compile::Error::expected_meta( ast, - meta.info(cx.q.pool), + meta.info(cx.q.pool)?, "something that can be called as a function", )); } @@ -1716,11 +1721,11 @@ fn expr_call<'hir>( let hash = match expr_field { hir::ExprField::Index(index) => Hash::index(index), hir::ExprField::Ident(ident) => { - cx.q.unit.insert_debug_ident(ident); + cx.q.unit.insert_debug_ident(ident)?; Hash::ident(ident) } hir::ExprField::IdentGenerics(ident, hash) => { - cx.q.unit.insert_debug_ident(ident); + cx.q.unit.insert_debug_ident(ident)?; Hash::ident(ident).with_function_parameters(hash) } }; diff --git a/crates/rune/src/hir/scopes.rs b/crates/rune/src/hir/scopes.rs index 98ee1b771..e43d94a2a 100644 --- a/crates/rune/src/hir/scopes.rs +++ b/crates/rune/src/hir/scopes.rs @@ -4,11 +4,13 @@ use core::cell::RefCell; use core::fmt; use core::num::NonZeroUsize; -use crate::no_std::collections::{BTreeSet, HashSet}; use crate::no_std::prelude::*; use crate::no_std::vec::Vec; +use crate::alloc::{self, BTreeSet, HashSet}; +use crate::ast::Spanned; use crate::compile::error::{MissingScope, PopError}; +use crate::compile::{self, HasSpan}; use crate::hir; use rune_macros::instrument; @@ -71,6 +73,18 @@ impl<'hir> Scopes<'hir> { /// Root scope. pub const ROOT: Scope = Scope(0); + #[inline] + pub(crate) fn new() -> alloc::Result { + let mut scopes = slab::Slab::new(); + scopes.insert(Layer::default()); + + Ok(Self { + scope: Scopes::ROOT, + scopes, + ids: 0, + }) + } + /// Push a scope. pub(crate) fn push(&mut self) { self.push_kind(LayerKind::Default, None) @@ -125,28 +139,36 @@ impl<'hir> Scopes<'hir> { pub(crate) fn define( &mut self, name: hir::Name<'hir>, - ) -> Result, MissingScope> { + span: &dyn Spanned, + ) -> compile::Result> { tracing::trace!(?self.scope, ?name, "define"); let Some(layer) = self.scopes.get_mut(self.scope.0) else { - return Err(MissingScope(self.scope.0)); + return Err(HasSpan::new(span, MissingScope(self.scope.0)).into()); }; - layer.variables.insert(name); + layer.variables.try_insert(name)?; layer.order.push(name); Ok(name) } /// Try to lookup the given variable. #[tracing::instrument(skip_all, fields(?self.scope, ?name))] - pub(crate) fn get(&mut self, name: hir::Name<'hir>) -> Option<(hir::Name<'hir>, Scope)> { + pub(crate) fn get( + &mut self, + name: hir::Name<'hir>, + ) -> alloc::Result, Scope)>> { tracing::trace!("get"); let mut blocks = Vec::new(); let mut scope = self.scopes.get(self.scope.0); let scope = 'ok: { - while let Some(layer) = scope.take() { + loop { + let Some(layer) = scope.take() else { + return Ok(None); + }; + if layer.variables.contains(&name) { break 'ok layer.scope; } @@ -156,10 +178,13 @@ impl<'hir> Scopes<'hir> { } tracing::trace!(parent = ?layer.parent()); - scope = self.scopes.get(layer.parent()?); - } - return None; + let Some(parent) = layer.parent() else { + return Ok(None); + }; + + scope = self.scopes.get(parent); + } }; for s in blocks { @@ -167,10 +192,10 @@ impl<'hir> Scopes<'hir> { continue; }; - layer.captures.insert(name); + layer.captures.try_insert(name)?; } - Some((name, scope)) + Ok(Some((name, scope))) } /// Walk the loop and construct captures for it. @@ -196,17 +221,3 @@ impl<'hir> Scopes<'hir> { None } } - -impl<'hir> Default for Scopes<'hir> { - #[inline] - fn default() -> Self { - let mut scopes = slab::Slab::new(); - scopes.insert(Layer::default()); - - Self { - scope: Scopes::ROOT, - scopes, - ids: 0, - } - } -} diff --git a/crates/rune/src/indexing.rs b/crates/rune/src/indexing.rs index 5f50ed9b5..7088845e6 100644 --- a/crates/rune/src/indexing.rs +++ b/crates/rune/src/indexing.rs @@ -2,9 +2,9 @@ pub(crate) mod index; pub(crate) mod items; mod scopes; -use crate::no_std::prelude::*; - use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::Box; use crate::ast::{self, Span, Spanned}; use crate::compile::meta; use crate::compile::{ItemId, ItemMeta}; @@ -15,7 +15,7 @@ pub(crate) use self::index::{IndexItem, Indexer}; pub(crate) use self::items::Items; pub(crate) use self::scopes::{Layer, Scopes}; -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct Entry { /// The query item this indexed entry belongs to. pub(crate) item_meta: ItemMeta, @@ -34,7 +34,7 @@ impl Entry { } /// An entry that has been indexed. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) enum Indexed { /// An enum. Enum, @@ -57,7 +57,7 @@ pub(crate) enum Indexed { } /// The ast of a function. -#[derive(Debug, Clone, Spanned)] +#[derive(Debug, TryClone, Spanned)] pub(crate) enum FunctionAst { /// An empty function body. Empty(Box, #[rune(span)] Span), @@ -76,7 +76,7 @@ impl FunctionAst { } } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct Function { /// Ast for declaration. pub(crate) ast: FunctionAst, @@ -93,7 +93,8 @@ pub(crate) struct Function { pub(crate) impl_item: Option, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) struct Import { /// The import entry. pub(crate) entry: meta::Import, @@ -103,13 +104,13 @@ pub(crate) struct Import { pub(crate) wildcard: bool, } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct Struct { /// The ast of the struct. pub(crate) ast: Box, } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct Variant { /// Id of of the enum type. pub(crate) enum_id: NonZeroId, @@ -119,7 +120,7 @@ pub(crate) struct Variant { pub(crate) index: usize, } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct Closure { /// Ast for closure. pub(crate) ast: Box, @@ -127,7 +128,7 @@ pub(crate) struct Closure { pub(crate) call: Call, } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct AsyncBlock { /// Ast for block. pub(crate) ast: ast::Block, @@ -135,17 +136,17 @@ pub(crate) struct AsyncBlock { pub(crate) call: Call, } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct ConstExpr { pub(crate) ast: Box, } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct ConstBlock { pub(crate) ast: Box, } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct ConstFn { /// The const fn ast. pub(crate) item_fn: Box, diff --git a/crates/rune/src/indexing/index.rs b/crates/rune/src/indexing/index.rs index 1f96bfd94..a6b19ec41 100644 --- a/crates/rune/src/indexing/index.rs +++ b/crates/rune/src/indexing/index.rs @@ -2,10 +2,9 @@ use core::num::NonZeroUsize; use core::mem::{replace, take}; -use crate::no_std::collections::{HashMap, VecDeque}; -use crate::no_std::path::PathBuf; -use crate::no_std::prelude::*; - +use crate::alloc::path::PathBuf; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, HashMap, Vec, VecDeque}; use crate::ast::spanned; use crate::ast::{self, OptionSpanned, Span, Spanned}; use crate::compile::attrs; @@ -161,7 +160,7 @@ impl<'a, 'arena> Indexer<'a, 'arena> { let mut exprs = Vec::new(); while !p.is_eof()? { - exprs.push(p.parse::()?); + exprs.try_push(p.parse::()?)?; if p.parse::>()?.is_none() { break; @@ -335,7 +334,7 @@ impl<'a, 'arena> Indexer<'a, 'arena> { }, ) })?; - let id = self.q.storage.insert_str(name); + let id = self.q.storage.insert_str(name)?; let source = ast::StrSource::Synthetic(id); let value = ast::Lit::Str(ast::LitStr { span: ast.span(), @@ -354,7 +353,8 @@ impl<'a, 'arena> Indexer<'a, 'arena> { .map(|s| s.pos_to_utf16cu_linecol(ast.open.span.start.into_usize())) .unwrap_or_default(); - let id = self.q.storage.insert_number(l + 1); // 1-indexed as that is what most editors will use + // 1-indexed as that is what most editors will use + let id = self.q.storage.insert_number(l + 1)?; let source = ast::NumberSource::Synthetic(id); Ok(BuiltInMacro::Line(BuiltInLine { @@ -366,17 +366,17 @@ impl<'a, 'arena> Indexer<'a, 'arena> { } /// Get or insert an item id. - fn item_id(&mut self) -> NonZeroId { + fn item_id(&mut self) -> alloc::Result { if let Some(id) = self.item.id { - return id; + return Ok(id); } let id = self .q - .insert_path(self.item.module, self.item.impl_item, self.items.item()); + .insert_path(self.item.module, self.item.impl_item, self.items.item())?; self.item.id = Some(id); - id + Ok(id) } /// Perform a macro expansion. @@ -384,7 +384,7 @@ impl<'a, 'arena> Indexer<'a, 'arena> { where T: Parse, { - ast.path.id.set(self.item_id()); + ast.path.id.set(self.item_id()?); let id = self.items.id().with_span(&ast)?; let item = self.q.item_for(id).with_span(&ast)?; @@ -406,7 +406,7 @@ impl<'a, 'arena> Indexer<'a, 'arena> { where T: Parse, { - attr.path.id.set(self.item_id()); + attr.path.id.set(self.item_id()?); let id = self.items.id().with_span(&*attr)?; @@ -430,7 +430,7 @@ impl<'a, 'arena> Indexer<'a, 'arena> { let visibility = ast_to_visibility(&item_mod.visibility)?; - let guard = self.items.push_name(name.as_ref()); + let guard = self.items.push_name(name.as_ref())?; let idx_item = self.item.replace(); let mod_item_id = self.items.id().with_span(&*item_mod)?; @@ -461,11 +461,13 @@ impl<'a, 'arena> Indexer<'a, 'arena> { .load(root, self.q.pool.module_item(mod_item), &*item_mod)?; if let Some(loaded) = self.loaded.as_mut() { - if let Some(_existing) = loaded.insert(mod_item, (self.source_id, item_mod.span())) { + if let Some(_existing) = + loaded.try_insert(mod_item, (self.source_id, item_mod.span()))? + { return Err(compile::Error::new( &*item_mod, ErrorKind::ModAlreadyLoaded { - item: self.q.pool.module_item(mod_item).to_owned(), + item: self.q.pool.module_item(mod_item).try_to_owned()?, #[cfg(feature = "emit")] existing: _existing, }, @@ -473,21 +475,22 @@ impl<'a, 'arena> Indexer<'a, 'arena> { } } - let source_id = self.q.sources.insert(source); + let source_id = self.q.sources.insert(source)?; self.q .visitor - .visit_mod(&DynLocation::new(source_id, &*item_mod)); + .visit_mod(&DynLocation::new(source_id, &*item_mod)) + .with_span(&*item_mod)?; if let Some(queue) = self.queue.as_mut() { - queue.push_back(Task::LoadFile { + queue.try_push_back(Task::LoadFile { kind: LoadFileKind::Module { root: self.root.clone(), }, source_id, mod_item, mod_item_id, - }); + })?; } Ok(()) @@ -502,12 +505,15 @@ pub(crate) fn file(idx: &mut Indexer<'_, '_>, ast: &mut ast::File) -> compile::R for doc in p.parse_all::(resolve_context!(idx.q), &ast.attributes) { let (span, doc) = doc?; - idx.q.visitor.visit_doc_comment( - &DynLocation::new(idx.source_id, &span), - idx.q.pool.module_item(idx.item.module), - idx.q.pool.module_item_hash(idx.item.module), - &doc.doc_string.resolve(resolve_context!(idx.q))?, - ); + idx.q + .visitor + .visit_doc_comment( + &DynLocation::new(idx.source_id, &span), + idx.q.pool.module_item(idx.item.module), + idx.q.pool.module_item_hash(idx.item.module), + &doc.doc_string.resolve(resolve_context!(idx.q))?, + ) + .with_span(span)?; } if let Some(first) = p.remaining(&ast.attributes).next() { @@ -527,13 +533,13 @@ pub(crate) fn file(idx: &mut Indexer<'_, '_>, ast: &mut ast::File) -> compile::R for (item, semi) in ast.items.drain(..) { match item { i @ ast::Item::MacroCall(_) => { - queue.push_back((0, i, Vec::new(), semi)); + queue.try_push_back((0, i, Vec::new(), semi))?; } i if !i.attributes().is_empty() => { - queue.push_back((0, i, Vec::new(), semi)); + queue.try_push_back((0, i, Vec::new(), semi))?; } i => { - head.push_back((i, semi)); + head.try_push_back((i, semi))?; } } } @@ -568,17 +574,17 @@ pub(crate) fn file(idx: &mut Indexer<'_, '_>, ast: &mut ast::File) -> compile::R // below. if let Some(mut attr) = item.remove_first_attribute() { let Some(file) = idx.expand_attribute_macro::(&mut attr, &item)? else { - skipped_attributes.push(attr); + skipped_attributes.try_push(attr)?; if !matches!(item, ast::Item::MacroCall(_)) && item.attributes().is_empty() { // For all we know only non macro attributes remain, which will be // handled by the item handler. *item.attributes_mut() = skipped_attributes; - head.push_front((item, semi)); + head.try_push_front((item, semi))?; } else { // items with remaining attributes and macro calls will be dealt with by // reinserting in the queue. - queue.push_back((depth, item, skipped_attributes, semi)) + queue.try_push_back((depth, item, skipped_attributes, semi))?; } continue; @@ -587,13 +593,13 @@ pub(crate) fn file(idx: &mut Indexer<'_, '_>, ast: &mut ast::File) -> compile::R for (item, semi) in file.items.into_iter().rev() { match item { item @ ast::Item::MacroCall(_) => { - queue.push_back((depth.wrapping_add(1), item, Vec::new(), semi)); + queue.try_push_back((depth.wrapping_add(1), item, Vec::new(), semi))?; } item if !item.attributes().is_empty() => { - queue.push_back((depth.wrapping_add(1), item, Vec::new(), semi)); + queue.try_push_back((depth.wrapping_add(1), item, Vec::new(), semi))?; } item => { - head.push_front((item, semi)); + head.try_push_front((item, semi))?; } } } @@ -621,7 +627,8 @@ pub(crate) fn file(idx: &mut Indexer<'_, '_>, ast: &mut ast::File) -> compile::R } // Macro call must be added to output to make sure its instructions are assembled. - ast.items.push((ast::Item::MacroCall(macro_call), semi)); + ast.items + .try_push((ast::Item::MacroCall(macro_call), semi))?; } else { if let Some(attr) = p.remaining(¯o_call.attributes).next() { return Err(compile::Error::msg( @@ -635,13 +642,13 @@ pub(crate) fn file(idx: &mut Indexer<'_, '_>, ast: &mut ast::File) -> compile::R for (item, semi) in file.items.into_iter().rev() { match item { item @ ast::Item::MacroCall(_) => { - queue.push_back((depth.wrapping_add(1), item, Vec::new(), semi)); + queue.try_push_back((depth.wrapping_add(1), item, Vec::new(), semi))?; } item if !item.attributes().is_empty() => { - queue.push_back((depth.wrapping_add(1), item, Vec::new(), semi)); + queue.try_push_back((depth.wrapping_add(1), item, Vec::new(), semi))?; } item => { - head.push_front((item, semi)); + head.try_push_front((item, semi))?; } } } @@ -662,7 +669,7 @@ pub(crate) fn empty_block_fn( mut ast: ast::EmptyBlock, span: &dyn Spanned, ) -> compile::Result<()> { - let guard = idx.items.push_id(); + let guard = idx.items.push_id()?; let idx_item = idx.item.replace(); let item_meta = idx.q.insert_new_item( @@ -691,7 +698,7 @@ pub(crate) fn empty_block_fn( idx.q.index_and_build(indexing::Entry { item_meta, indexed: Indexed::Function(indexing::Function { - ast: indexing::FunctionAst::Empty(Box::new(ast), span.span()), + ast: indexing::FunctionAst::Empty(Box::try_new(ast)?, span.span()), call, is_instance: false, is_test: false, @@ -716,7 +723,7 @@ pub(crate) fn item_fn_immediate( let docs = Doc::collect_from(resolve_context!(idx.q), &mut p, &ast.attributes)?; - let guard = idx.items.push_name(name.as_ref()); + let guard = idx.items.push_name(name.as_ref())?; let idx_item = idx.item.replace(); let item_meta = idx.q.insert_new_item( @@ -755,7 +762,7 @@ pub(crate) fn item_fn_immediate( let call = validate_call(ast.const_token.as_ref(), ast.async_token.as_ref(), &layer)?; let Some(call) = call else { - idx.q.index_const_fn(item_meta, Box::new(ast))?; + idx.q.index_const_fn(item_meta, Box::try_new(ast)?)?; return Ok(()); }; @@ -830,7 +837,7 @@ pub(crate) fn item_fn_immediate( let entry = indexing::Entry { item_meta, indexed: Indexed::Function(indexing::Function { - ast: indexing::FunctionAst::Item(Box::new(ast)), + ast: indexing::FunctionAst::Item(Box::try_new(ast)?), call, is_instance, is_test, @@ -863,8 +870,10 @@ fn item_fn(idx: &mut Indexer<'_, '_>, ast: ast::ItemFn) -> compile::Result<()> { .inner .impl_functions .entry(impl_item) - .or_default() - .push(QueryImplFn { ast: Box::new(ast) }); + .or_try_default()? + .try_push(QueryImplFn { + ast: Box::try_new(ast)?, + })?; } else { item_fn_immediate(idx, ast)?; } @@ -892,7 +901,7 @@ fn expr_block(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprBlock) -> compile::R return block(idx, &mut ast.block); } - let guard = idx.items.push_id(); + let guard = idx.items.push_id()?; let idx_item = idx.item.replace(); let item_meta = idx.q.insert_new_item( @@ -958,7 +967,7 @@ fn statements(idx: &mut Indexer<'_, '_>, ast: &mut Vec) -> compile::R item(idx, i)?; } stmt => { - statements.push(stmt); + statements.try_push(stmt)?; } } } @@ -1008,7 +1017,7 @@ fn statements(idx: &mut Indexer<'_, '_>, ast: &mut Vec) -> compile::R #[instrument(span = ast)] fn block(idx: &mut Indexer<'_, '_>, ast: &mut ast::Block) -> compile::Result<()> { - let guard = idx.items.push_id(); + let guard = idx.items.push_id()?; let idx_item = idx.item.replace(); idx.q.insert_new_item( @@ -1342,7 +1351,7 @@ fn item_enum(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemEnum) -> compile::Resu } let name = ast.name.resolve(resolve_context!(idx.q))?; - let guard = idx.items.push_name(name.as_ref()); + let guard = idx.items.push_name(name.as_ref())?; let idx_item = idx.item.replace(); let visibility = ast_to_visibility(&ast.visibility)?; @@ -1369,7 +1378,7 @@ fn item_enum(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemEnum) -> compile::Resu } let name = variant.name.resolve(resolve_context!(idx.q))?; - let guard = idx.items.push_name(name.as_ref()); + let guard = idx.items.push_name(name.as_ref())?; let idx_item = idx.item.replace(); let item_meta = idx.q.insert_new_item( @@ -1398,13 +1407,16 @@ fn item_enum(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemEnum) -> compile::Resu let name = field.name.resolve(cx)?; for doc in docs { - idx.q.visitor.visit_field_doc_comment( - &DynLocation::new(idx.source_id, &doc), - idx.q.pool.item(item_meta.item), - idx.q.pool.item_type_hash(item_meta.item), - name, - doc.doc_string.resolve(cx)?.as_ref(), - ); + idx.q + .visitor + .visit_field_doc_comment( + &DynLocation::new(idx.source_id, &doc), + idx.q.pool.item(item_meta.item), + idx.q.pool.item_type_hash(item_meta.item), + name, + doc.doc_string.resolve(cx)?.as_ref(), + ) + .with_span(doc)?; } } @@ -1433,7 +1445,7 @@ fn item_struct(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemStruct) -> compile:: } let ident = ast.ident.resolve(resolve_context!(idx.q))?; - let guard = idx.items.push_name(ident); + let guard = idx.items.push_name(ident)?; let idx_item = idx.item.replace(); let visibility = ast_to_visibility(&ast.visibility)?; @@ -1462,13 +1474,16 @@ fn item_struct(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemStruct) -> compile:: let name = field.name.resolve(cx)?; for doc in docs { - idx.q.visitor.visit_field_doc_comment( - &DynLocation::new(idx.source_id, &doc), - idx.q.pool.item(item_meta.item), - idx.q.pool.item_type_hash(item_meta.item), - name, - doc.doc_string.resolve(cx)?.as_ref(), - ); + idx.q + .visitor + .visit_field_doc_comment( + &DynLocation::new(idx.source_id, &doc), + idx.q.pool.item(item_meta.item), + idx.q.pool.item_type_hash(item_meta.item), + name, + doc.doc_string.resolve(cx)?.as_ref(), + ) + .with_span(doc)?; } if !field.visibility.is_inherited() { @@ -1481,7 +1496,7 @@ fn item_struct(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemStruct) -> compile:: idx.item = idx_item; idx.items.pop(guard).with_span(&ast)?; - idx.q.index_struct(item_meta, Box::new(ast))?; + idx.q.index_struct(item_meta, Box::try_new(ast)?)?; Ok(()) } @@ -1499,14 +1514,14 @@ fn item_impl(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemImpl) -> compile::Resu let location = Location::new(idx.source_id, ast.path.span()); let id = idx.q.gen.next(); - idx.q.inner.impl_item_queue.push_back(ItemImplEntry { - path: Box::new(ast.path), + idx.q.inner.impl_item_queue.try_push_back(ItemImplEntry { + path: Box::try_new(ast.path)?, location, id, root: idx.root.clone(), nested_item: idx.nested_item, macro_depth: idx.macro_depth, - }); + })?; let idx_item = idx.item.replace_impl(id); @@ -1539,7 +1554,7 @@ fn item_mod(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemMod) -> compile::Result } ast::ItemModBody::InlineBody(body) => { let name = ast.name.resolve(resolve_context!(idx.q))?; - let guard = idx.items.push_name(name.as_ref()); + let guard = idx.items.push_name(name.as_ref())?; let idx_item = idx.item.replace(); let visibility = ast_to_visibility(&ast.visibility)?; @@ -1582,7 +1597,7 @@ fn item_const(idx: &mut Indexer<'_, '_>, mut ast: ast::ItemConst) -> compile::Re } let name = ast.name.resolve(resolve_context!(idx.q))?; - let guard = idx.items.push_name(name.as_ref()); + let guard = idx.items.push_name(name.as_ref())?; let idx_item = idx.item.replace(); let item_meta = idx.q.insert_new_item( @@ -1667,13 +1682,14 @@ fn item(idx: &mut Indexer<'_, '_>, ast: ast::Item) -> compile::Result<()> { kind: ImportKind::Global, visibility, module: idx.item.module, - item: idx.items.item().clone(), + item: idx.items.item().try_clone()?, source_id: idx.source_id, - ast: Box::new(item_use), + ast: Box::try_new(item_use)?, }; import.process(&mut idx.q, &mut |task| { - queue.push_back(task); + queue.try_push_back(task)?; + Ok(()) })?; } } @@ -1683,7 +1699,7 @@ fn item(idx: &mut Indexer<'_, '_>, ast: ast::Item) -> compile::Result<()> { #[instrument(span = ast)] fn path(idx: &mut Indexer<'_, '_>, ast: &mut ast::Path) -> compile::Result<()> { - ast.id.set(idx.item_id()); + ast.id.set(idx.item_id()?); path_segment(idx, &mut ast.first)?; @@ -1728,7 +1744,7 @@ fn expr_for(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprFor) -> compile::Resul #[instrument(span = ast)] fn expr_closure(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprClosure) -> compile::Result<()> { - let guard = idx.items.push_id(); + let guard = idx.items.push_id()?; let idx_item = idx.item.replace(); idx.scopes.push(); @@ -1824,9 +1840,8 @@ fn expr_continue(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprContinue) -> comp #[instrument(span = ast)] fn expr_yield(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprYield) -> compile::Result<()> { - idx.scopes - .mark(|l| l.yields.push(ast.span())) - .with_span(&*ast)?; + let l = idx.scopes.mark().with_span(&*ast)?; + l.yields.try_push(ast.span())?; if let Some(e) = &mut ast.expr { expr(idx, e)?; @@ -1846,9 +1861,8 @@ fn expr_return(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprReturn) -> compile: #[instrument(span = ast)] fn expr_await(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprAwait) -> compile::Result<()> { - idx.scopes - .mark(|l| l.awaits.push(ast.span())) - .with_span(&*ast)?; + let l = idx.scopes.mark().with_span(&*ast)?; + l.awaits.try_push(ast.span())?; expr(idx, &mut ast.expr)?; Ok(()) @@ -1862,9 +1876,8 @@ fn expr_try(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprTry) -> compile::Resul #[instrument(span = ast)] fn expr_select(idx: &mut Indexer<'_, '_>, ast: &mut ast::ExprSelect) -> compile::Result<()> { - idx.scopes - .mark(|l| l.awaits.push(ast.span())) - .with_span(&*ast)?; + let l = idx.scopes.mark().with_span(&*ast)?; + l.awaits.try_push(ast.span())?; for (branch, _) in &mut ast.branches { match branch { diff --git a/crates/rune/src/indexing/items.rs b/crates/rune/src/indexing/items.rs index d9b3f6224..dc6b0d6b8 100644 --- a/crates/rune/src/indexing/items.rs +++ b/crates/rune/src/indexing/items.rs @@ -1,9 +1,9 @@ use core::fmt; use core::mem::replace; -use crate::no_std::prelude::*; - -use crate::compile::{ComponentRef, Item, ItemBuf}; +use crate::alloc; +use crate::alloc::prelude::*; +use crate::compile::{ComponentRef, ErrorKind, Item, ItemBuf}; use crate::parse::NonZeroId; use crate::shared::Gen; @@ -53,13 +53,13 @@ pub(crate) struct Items<'a> { impl<'a> Items<'a> { /// Construct a new items manager. - pub(crate) fn new(item: &Item, id: NonZeroId, gen: &'a Gen) -> Self { - Self { + pub(crate) fn new(item: &Item, id: NonZeroId, gen: &'a Gen) -> alloc::Result { + Ok(Self { block_index: item.last().and_then(ComponentRef::id).unwrap_or_default(), - item: item.to_owned(), + item: item.try_to_owned()?, last_id: id, gen, - } + }) } /// Access the last added id. @@ -73,37 +73,37 @@ impl<'a> Items<'a> { } /// Push a component and return a guard to it. - pub(crate) fn push_id(&mut self) -> Guard { + pub(crate) fn push_id(&mut self) -> alloc::Result { let id = self.gen.next(); let next_index = self.block_index; - self.item.push(ComponentRef::Id(next_index)); + self.item.push(ComponentRef::Id(next_index))?; let last_id = replace(&mut self.last_id, id); - Guard(id, last_id) + Ok(Guard(id, last_id)) } /// Push a component and return a guard to it. - pub(crate) fn push_name(&mut self, name: &str) -> Guard { + pub(crate) fn push_name(&mut self, name: &str) -> alloc::Result { let id = self.gen.next(); self.block_index = 0; - self.item.push(name); + self.item.push(name)?; let last_id = replace(&mut self.last_id, id); - Guard(id, last_id) + Ok(Guard(id, last_id)) } /// Pop the scope associated with the given guard. - pub(crate) fn pop(&mut self, guard: Guard) -> Result<(), GuardMismatch> { + pub(crate) fn pop(&mut self, guard: Guard) -> Result<(), ErrorKind> { let Guard(expected_id, last_id) = guard; if self.last_id != expected_id { - return Err(GuardMismatch { + return Err(ErrorKind::from(GuardMismatch { actual: self.last_id, expected: expected_id, - }); + })); } self.block_index = self .item - .pop() + .pop()? .and_then(|c| c.id()) .and_then(|n| n.checked_add(1)) .unwrap_or_default(); diff --git a/crates/rune/src/indexing/scopes.rs b/crates/rune/src/indexing/scopes.rs index b5bf7bce0..979b623ac 100644 --- a/crates/rune/src/indexing/scopes.rs +++ b/crates/rune/src/indexing/scopes.rs @@ -4,10 +4,7 @@ use core::cell::RefCell; use core::fmt; use core::num::NonZeroUsize; -use crate::no_std::collections::BTreeSet; -use crate::no_std::collections::HashMap; -use crate::no_std::vec::Vec; - +use crate::alloc::{self, BTreeSet, HashMap, Vec}; use crate::ast::Span; use crate::compile::error::{MissingScope, PopError}; @@ -52,6 +49,16 @@ impl Scopes { /// Root scope. pub const ROOT: Scope = Scope(0); + pub(crate) fn new() -> alloc::Result { + let mut scopes = slab::Slab::new(); + scopes.insert(Layer::default()); + + Ok(Self { + scope: Scopes::ROOT, + scopes, + }) + } + /// Push a scope. pub(crate) fn push(&mut self) { let scope = Scope(self.scopes.vacant_key()); @@ -83,30 +90,13 @@ impl Scopes { /// Define the given variable. #[tracing::instrument(skip_all)] - pub(crate) fn mark(&mut self, f: F) -> Result<(), MissingScope> - where - F: FnOnce(&mut Layer), - { + pub(crate) fn mark(&mut self) -> Result<&mut Layer, MissingScope> { tracing::trace!(?self.scope, "mark await"); let Some(layer) = self.scopes.get_mut(self.scope.0) else { return Err(MissingScope(self.scope.0)); }; - f(layer); - Ok(()) - } -} - -impl Default for Scopes { - #[inline] - fn default() -> Self { - let mut scopes = slab::Slab::new(); - scopes.insert(Layer::default()); - - Self { - scope: Scopes::ROOT, - scopes, - } + Ok(layer) } } diff --git a/crates/rune/src/languageserver.rs b/crates/rune/src/languageserver.rs index 8a222b216..9971e0933 100644 --- a/crates/rune/src/languageserver.rs +++ b/crates/rune/src/languageserver.rs @@ -19,8 +19,8 @@ use tokio::sync::Notify; use crate::languageserver::connection::stdio; use crate::languageserver::envelope::Code; use crate::languageserver::state::State; +use crate::support::Result; use crate::workspace::MANIFEST_FILE; -use crate::Result; use crate::{Context, Options}; enum Language { @@ -210,13 +210,15 @@ async fn completion( state: &mut State<'_>, params: lsp::CompletionParams, ) -> Result> { - let results = state.complete( + let Some(results) = state.complete( ¶ms.text_document_position.text_document.uri, params.text_document_position.position, - ); + )? + else { + return Ok(None); + }; - let results = results.map(lsp::CompletionResponse::Array); - Ok(results) + Ok(Some(lsp::CompletionResponse::Array(results.into_std()))) } /// Handle formatting request. @@ -242,9 +244,9 @@ async fn did_open_text_document( if s.workspace_mut() .insert_source( params.text_document.uri.clone(), - params.text_document.text, + params.text_document.text.try_into()?, lagnuage, - ) + )? .is_some() { tracing::warn!( @@ -290,7 +292,7 @@ async fn did_close_text_document( s: &mut State<'_>, params: lsp::DidCloseTextDocumentParams, ) -> Result<()> { - s.workspace_mut().remove(¶ms.text_document.uri); + s.workspace_mut().remove(¶ms.text_document.uri)?; s.rebuild_interest(); Ok(()) } diff --git a/crates/rune/src/languageserver/completion.rs b/crates/rune/src/languageserver/completion.rs index 2688ca567..f026331e1 100644 --- a/crates/rune/src/languageserver/completion.rs +++ b/crates/rune/src/languageserver/completion.rs @@ -1,5 +1,4 @@ -use crate::no_std::prelude::*; - +use anyhow::Result; use lsp::CompletionItem; use lsp::CompletionItemKind; use lsp::CompletionItemLabelDetails; @@ -9,6 +8,9 @@ use lsp::MarkupContent; use lsp::MarkupKind; use lsp::TextEdit; +use crate::alloc::fmt::TryWrite; +use crate::alloc::prelude::*; +use crate::alloc::{String, Vec}; use crate::compile::meta; use crate::runtime::debug::DebugArgs; use crate::Context; @@ -22,25 +24,37 @@ pub(super) fn complete_for_unit( symbol: &str, position: lsp::Position, results: &mut Vec, -) { +) -> Result<()> { let Some(debug_info) = unit.debug_info() else { - return; + return Ok(()); }; for (hash, function) in debug_info.functions.iter() { - let func_name = function.to_string(); + let func_name = function.try_to_string()?; + if !func_name.starts_with(symbol) { continue; } let args = match &function.args { DebugArgs::EmptyArgs => None, - DebugArgs::TupleArgs(n) => Some( - (0..*n) - .map(|n| format!("_{}", n)) - .fold("".to_owned(), |a, b| format!("{}, {}", a, b)), - ), - DebugArgs::Named(names) => Some(names.join(", ")), + DebugArgs::TupleArgs(n) => Some({ + let mut o = String::new(); + + let mut it = 0..*n; + let last = it.next_back(); + + for n in it { + write!(o, "_{n}, ")?; + } + + if let Some(n) = last { + write!(o, "_{n}")?; + } + + o + }), + DebugArgs::Named(names) => Some(names.iter().map(|s| s.as_ref()).try_join(", ")?), }; let docs = workspace_source @@ -48,7 +62,8 @@ pub(super) fn complete_for_unit( .map(|docs| docs.docs.join("\n")); let detail = args.map(|a| format!("({a:}) -> ?")); - results.push(CompletionItem { + + results.try_push(CompletionItem { label: format!("{}", function.path.last().unwrap()), kind: Some(CompletionItemKind::FUNCTION), detail: detail.clone(), @@ -74,8 +89,10 @@ pub(super) fn complete_for_unit( }), commit_characters: Some(vec!["(".into()]), ..Default::default() - }) + })?; } + + Ok(()) } pub(super) fn complete_native_instance_data( @@ -83,7 +100,7 @@ pub(super) fn complete_native_instance_data( symbol: &str, position: lsp::Position, results: &mut Vec, -) { +) -> Result<()> { for (meta, signature) in context.iter_functions() { let (prefix, kind, n) = match (&meta.item, &meta.kind) { ( @@ -107,8 +124,8 @@ pub(super) fn complete_native_instance_data( let detail = return_type.map(|r| format!("({args} -> {r}")); - results.push(CompletionItem { - label: n.to_string(), + results.try_push(CompletionItem { + label: n.try_to_string()?.into_std(), kind: Some(kind), detail, documentation: Some(lsp::Documentation::MarkupContent(MarkupContent { @@ -123,17 +140,19 @@ pub(super) fn complete_native_instance_data( }, end: position, }, - new_text: n.to_string(), + new_text: n.try_to_string()?.into_std(), })), label_details: Some(CompletionItemLabelDetails { detail: None, - description: Some(prefix.to_string()), + description: Some(prefix.try_to_string()?.into_std()), }), data: Some(serde_json::to_value(meta.hash).unwrap()), ..Default::default() - }) + })?; } } + + Ok(()) } pub(super) fn complete_native_loose_data( @@ -141,16 +160,17 @@ pub(super) fn complete_native_loose_data( symbol: &str, position: lsp::Position, results: &mut Vec, -) { +) -> Result<()> { for (meta, signature) in context.iter_functions() { let (item, kind) = match (&meta.item, &meta.kind) { - (Some(item), meta::Kind::Function { .. }) => { - (item.clone(), CompletionItemKind::FUNCTION) - } + (Some(item), meta::Kind::Function { .. }) => (item, CompletionItemKind::FUNCTION), _ => continue, }; - let func_name = item.to_string().trim_start_matches("::").to_owned(); + let func_name = item + .try_to_string()? + .trim_start_matches("::") + .try_to_owned()?; if func_name.starts_with(symbol) { let return_type = signature @@ -163,8 +183,8 @@ pub(super) fn complete_native_loose_data( let detail = return_type.map(|r| format!("({args}) -> {r}")); - results.push(CompletionItem { - label: func_name.clone(), + results.try_push(CompletionItem { + label: func_name.try_clone()?.into_std(), kind: Some(kind), detail, documentation: Some(lsp::Documentation::MarkupContent(MarkupContent { @@ -179,11 +199,13 @@ pub(super) fn complete_native_loose_data( }, end: position, }, - new_text: func_name, + new_text: func_name.into_std(), })), data: Some(serde_json::to_value(meta.hash).unwrap()), ..Default::default() - }) + })?; } } + + Ok(()) } diff --git a/crates/rune/src/languageserver/state.rs b/crates/rune/src/languageserver/state.rs index 4014cb9ea..d2372b933 100644 --- a/crates/rune/src/languageserver/state.rs +++ b/crates/rune/src/languageserver/state.rs @@ -3,19 +3,19 @@ use std::fmt; use std::path::{Path, PathBuf}; use std::sync::Arc; -use crate::no_std::collections::HashMap; -use crate::no_std::prelude::*; - use anyhow::{anyhow, Context as _, Result}; use lsp::Url; use ropey::Rope; use tokio::sync::Notify; +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, HashMap, String, Vec}; use crate::ast::{Span, Spanned}; use crate::compile::meta; use crate::compile::{ - self, CompileVisitor, ComponentRef, Item, ItemBuf, LinkerError, Located, Location, MetaRef, - SourceMeta, + self, CompileVisitor, ComponentRef, Item, LinkerError, Located, Location, MetaError, MetaRef, + SourceMeta, WithSpan, }; use crate::diagnostics::{Diagnostic, FatalDiagnosticKind}; use crate::doc::VisitorData; @@ -50,7 +50,7 @@ struct Build { } impl Build { - pub(super) fn populate(&mut self, reporter: &mut Reporter) { + pub(super) fn populate(&mut self, reporter: &mut Reporter) -> Result<()> { for id in self.sources.source_ids() { let Some(source) = self.sources.get(id) else { continue; @@ -65,8 +65,10 @@ impl Build { }; reporter.ensure(&url); - self.id_to_url.insert(id, url); + self.id_to_url.try_insert(id, url)?; } + + Ok(()) } pub(super) fn visit(&mut self, visited: &mut HashSet) { @@ -201,21 +203,27 @@ impl<'a> State<'a> { &self, uri: &Url, position: lsp::Position, - ) -> Option> { + ) -> Result>> { let sources = &self.workspace.sources; tracing::trace!(uri = ?uri, uri_exists = sources.get(uri).is_some()); - let workspace_source = sources.get(uri)?; + + let Some(workspace_source) = sources.get(uri) else { + return Ok(None); + }; let offset = workspace_source.lsp_position_to_offset(position); - let (mut symbol, start) = workspace_source.looking_back(offset)?; + let Some((mut symbol, start)) = workspace_source.looking_back(offset)? else { + return Ok(None); + }; + tracing::trace!(symbol = ?symbol, start = ?start); if symbol.is_empty() { - return None; + return Ok(None); } - let mut results = vec![]; + let mut results = Vec::new(); let can_use_instance_fn: &[_] = &['.']; let first_char = symbol.remove(0); @@ -228,7 +236,7 @@ impl<'a> State<'a> { symbol, position, &mut results, - ); + )?; } if first_char.is_ascii_alphabetic() || can_use_instance_fn.contains(&first_char) { @@ -237,31 +245,34 @@ impl<'a> State<'a> { symbol, position, &mut results, - ); + )?; } else { super::completion::complete_native_loose_data( &self.context, symbol, position, &mut results, - ); + )?; } - Some(results) + Ok(Some(results)) } pub(super) fn format(&mut self, uri: &Url) -> Result> { let sources = &mut self.workspace.sources; - tracing::trace!(uri = ?uri, uri_exists = sources.get(uri).is_some()); + tracing::trace!(uri = ?uri.try_to_string()?, uri_exists = sources.get(uri).is_some()); + let Some(workspace_source) = sources.get_mut(uri) else { return Ok(None); }; - let source = workspace_source.content.to_string(); + let source = workspace_source.content.try_to_string()?; + let Ok(formatted) = crate::fmt::layout_source(&source) else { return Ok(None); }; - let formatted = String::from_utf8(formatted).context("format produced invalid utf8")?; + + let formatted = String::from_utf8(formatted).context("Format produced invalid utf8")?; // Only modify if changed Ok(if source != formatted { @@ -274,7 +285,7 @@ impl<'a> State<'a> { lsp::Position::new(0, 0), lsp::Position::new(u32::MAX, u32::MAX), ), - formatted, + formatted.into_std(), )) } else { None @@ -314,17 +325,18 @@ impl<'a> State<'a> { } Ok(script_builds) => { for script_build in script_builds { - script_results.push(self.build_scripts(script_build, Some(&mut visited))?); + script_results + .try_push(self.build_scripts(script_build, Some(&mut visited))?)?; } } }; - workspace_results.push((diagnostics, build)); + workspace_results.try_push((diagnostics, build))?; } for (url, source) in &self.workspace.sources { if visited.contains(url) { - tracing::trace!(url = url.to_string(), "already populated by workspace"); + tracing::trace!(url = ?url.try_to_string()?, "already populated by workspace"); continue; } @@ -332,17 +344,17 @@ impl<'a> State<'a> { continue; } - tracing::trace!(url = url.to_string(), "build plain source"); + tracing::trace!(url = ?url.try_to_string()?, "build plain source"); let mut build = Build::default(); let input = match url.to_file_path() { - Ok(path) => crate::Source::with_path(url, source.to_string(), path), - Err(..) => crate::Source::new(url, source.to_string()), + Ok(path) => crate::Source::with_path(url, source.try_to_string()?, path), + Err(..) => crate::Source::new(url, source.try_to_string()?), }; - build.sources.insert(input); - script_results.push(self.build_scripts(build, None)?); + build.sources.insert(input)?; + script_results.try_push(self.build_scripts(build, None)?)?; } // We need to pupulate diagnostics for everything we know about, in @@ -352,13 +364,13 @@ impl<'a> State<'a> { } for (diagnostics, mut build) in workspace_results { - build.populate(&mut reporter); - emit_workspace(diagnostics, &build, &mut reporter); + build.populate(&mut reporter)?; + emit_workspace(diagnostics, &build, &mut reporter)?; } for (diagnostics, mut build, source_visitor, doc_visitor, unit) in script_results { - build.populate(&mut reporter); - emit_scripts(diagnostics, &build, &mut reporter); + build.populate(&mut reporter)?; + emit_scripts(diagnostics, &build, &mut reporter)?; let sources = Arc::new(build.sources); let doc_visitor = Arc::new(doc_visitor); @@ -375,8 +387,8 @@ impl<'a> State<'a> { source.index = value; source.build_sources = Some(sources.clone()); - if let Ok(unit) = unit.as_ref().map(|v| v.clone()) { - source.unit = Some(unit.clone()); + if let Ok(unit) = &unit { + source.unit = Some(unit.try_clone()?); } source.docs = Some(doc_visitor.clone()); @@ -384,11 +396,15 @@ impl<'a> State<'a> { } for (url, diagnostics) in reporter.by_url { - tracing::info!(url = ?url.to_string(), diagnostics = diagnostics.len(), "publishing diagnostics"); + tracing::info!( + url = ?url.try_to_string()?, + diagnostics = diagnostics.len(), + "publishing diagnostics" + ); let diagnostics = lsp::PublishDiagnosticsParams { uri: url.clone(), - diagnostics, + diagnostics: diagnostics.into_std(), version: None, }; @@ -409,16 +425,21 @@ impl<'a> State<'a> { diagnostics: &mut workspace::Diagnostics, workspace: &Workspace, ) -> Result, anyhow::Error> { - tracing::info!(url = ?url.to_string(), "building workspace"); + tracing::info!(url = ?url.try_to_string(), "building workspace"); let source = match workspace.sources.get(url) { - Some(source) => source.chunks().collect::(), - None => std::fs::read_to_string(path).with_context(|| url.to_string())?, + Some(source) => source.chunks().try_collect::()?, + None => match std::fs::read_to_string(path) { + Ok(source) => String::try_from(source)?, + Err(error) => { + return Err(error).context(url.try_to_string()?); + } + }, }; manifest_build .sources - .insert(crate::Source::with_path(url, source, path)); + .insert(crate::Source::with_path(url, source, path))?; let mut source_loader = WorkspaceSourceLoader::new(&self.workspace.sources); @@ -434,20 +455,22 @@ impl<'a> State<'a> { continue; }; - tracing::trace!("found manifest source: {}", url); + tracing::trace!("Found manifest source: {}", url); let source = match workspace.sources.get(&url) { - Some(source) => source.chunks().collect::(), - None => std::fs::read_to_string(&p.found.path) - .with_context(|| p.found.path.display().to_string())?, + Some(source) => source.chunks().try_collect::()?, + None => match std::fs::read_to_string(&p.found.path) { + Ok(string) => String::try_from(string)?, + Err(err) => return Err(err).context(p.found.path.display().try_to_string()?), + }, }; let mut build = Build::default(); build .sources - .insert(crate::Source::with_path(&url, source, p.found.path)); + .insert(crate::Source::with_path(&url, source, p.found.path))?; - script_builds.push(build); + script_builds.try_push(build)?; } Ok(script_builds) @@ -466,7 +489,7 @@ impl<'a> State<'a> { )> { let mut diagnostics = crate::Diagnostics::new(); let mut source_visitor = Visitor::default(); - let mut doc_visitor = crate::doc::Visitor::new(ItemBuf::new())?; + let mut doc_visitor = crate::doc::Visitor::new(Item::new())?; let mut source_loader = ScriptSourceLoader::new(&self.workspace.sources); @@ -474,8 +497,8 @@ impl<'a> State<'a> { .with_context(&self.context) .with_diagnostics(&mut diagnostics) .with_options(&self.options) - .with_visitor(&mut doc_visitor) - .with_visitor(&mut source_visitor) + .with_visitor(&mut doc_visitor)? + .with_visitor(&mut source_visitor)? .with_source_loader(&mut source_loader) .build(); @@ -488,13 +511,18 @@ impl<'a> State<'a> { } /// Emit diagnostics workspace. -fn emit_workspace(diagnostics: workspace::Diagnostics, build: &Build, reporter: &mut Reporter) { +fn emit_workspace( + diagnostics: workspace::Diagnostics, + build: &Build, + reporter: &mut Reporter, +) -> Result<()> { if tracing::enabled!(tracing::Level::TRACE) { let id_to_url = build .id_to_url .iter() - .map(|(k, v)| (*k, v.to_string())) - .collect::>(); + .map(|(k, v)| Ok::<_, alloc::Error>((*k, v.try_to_string()?))) + .try_collect::, _>>()??; + tracing::trace!(?id_to_url, "emitting manifest diagnostics"); } @@ -502,18 +530,24 @@ fn emit_workspace(diagnostics: workspace::Diagnostics, build: &Build, reporter: tracing::trace!(?diagnostic, "workspace diagnostic"); let workspace::Diagnostic::Fatal(f) = diagnostic; - report(build, reporter, f.source_id(), f.error(), to_error); + report(build, reporter, f.source_id(), f.error(), to_error)?; } + + Ok(()) } /// Emit regular compile diagnostics. -fn emit_scripts(diagnostics: crate::Diagnostics, build: &Build, reporter: &mut Reporter) { +fn emit_scripts( + diagnostics: crate::Diagnostics, + build: &Build, + reporter: &mut Reporter, +) -> Result<()> { if tracing::enabled!(tracing::Level::TRACE) { let id_to_url = build .id_to_url .iter() - .map(|(k, v)| (*k, v.to_string())) - .collect::>(); + .map(|(k, v)| Ok::<_, alloc::Error>((*k, v.try_to_string()?))) + .try_collect::, _>>()??; tracing::trace!(?id_to_url, "emitting script diagnostics"); } @@ -524,7 +558,7 @@ fn emit_scripts(diagnostics: crate::Diagnostics, build: &Build, reporter: &mut R match diagnostic { Diagnostic::Fatal(f) => match f.kind() { FatalDiagnosticKind::CompileError(e) => { - report(build, reporter, f.source_id(), e, to_error); + report(build, reporter, f.source_id(), e, to_error)?; } FatalDiagnosticKind::LinkError(e) => match e { LinkerError::MissingFunction { hash, spans } => { @@ -542,22 +576,24 @@ fn emit_scripts(diagnostics: crate::Diagnostics, build: &Build, reporter: &mut R let diagnostics = reporter.entry(url); - diagnostics.push(to_error( + diagnostics.try_push(to_error( range, - format!("missing function with hash `{}`", hash), - )); + format_args!("Missing function with hash `{}`", hash), + )?)?; } } }, FatalDiagnosticKind::Internal(e) => { - report_without_span(build, reporter, f.source_id(), e, to_error); + report_without_span(build, reporter, f.source_id(), e, to_error)?; } }, Diagnostic::Warning(e) => { - report(build, reporter, e.source_id(), e, to_warning); + report(build, reporter, e.source_id(), e, to_warning)?; } } } + + Ok(()) } /// A collection of open sources. @@ -578,16 +614,17 @@ impl Workspace { url: Url, text: String, language: Language, - ) -> Option { + ) -> alloc::Result> { let source = Source { - content: Rope::from(text), + content: Rope::from_str(text.as_str()), index: Default::default(), build_sources: None, language, unit: None, docs: None, }; - self.sources.insert(url, source) + + self.sources.try_insert(url, source) } /// Get the source at the given url. @@ -601,10 +638,12 @@ impl Workspace { } /// Remove the given url as a source. - pub(super) fn remove(&mut self, url: &Url) { + pub(super) fn remove(&mut self, url: &Url) -> Result<()> { if self.sources.remove(url).is_some() { - self.removed.push(url.clone()); + self.removed.try_push(url.clone())?; } + + Ok(()) } } @@ -664,7 +703,7 @@ impl Source { } /// Returns the best match wordwise when looking back. Note that this will also include the *previous* terminal token. - pub fn looking_back(&self, offset: usize) -> Option<(String, usize)> { + pub(crate) fn looking_back(&self, offset: usize) -> alloc::Result> { let (chunk, start_byte, _, _) = self.content.chunk_at_byte(offset); // The set of tokens that delimit symbols. @@ -673,12 +712,15 @@ impl Source { ]; let end_search = (offset - start_byte + 1).min(chunk.len()); - chunk[..end_search].rfind(x).map(|looking_back| { - ( - chunk[looking_back..end_search].trim().to_owned(), - start_byte + looking_back, - ) - }) + + let Some(looking_back) = chunk[..end_search].rfind(x) else { + return Ok(None); + }; + + Ok(Some(( + chunk[looking_back..end_search].trim().try_to_owned()?, + start_byte + looking_back, + ))) } pub(super) fn get_docs_by_hash(&self, hash: crate::Hash) -> Option<&VisitorData> { @@ -731,11 +773,17 @@ fn rope_utf16_position(rope: &Rope, position: lsp::Position) -> Result { } /// Convert the given span and error into an error diagnostic. -fn report(build: &Build, reporter: &mut Reporter, source_id: SourceId, error: E, report: R) +fn report( + build: &Build, + reporter: &mut Reporter, + source_id: SourceId, + error: E, + report: R, +) -> Result<()> where E: fmt::Display, E: Spanned, - R: Fn(lsp::Range, E) -> lsp::Diagnostic, + R: Fn(lsp::Range, E) -> alloc::Result, { let span = error.span(); @@ -743,14 +791,15 @@ where build.sources.get(source_id), build.id_to_url.get(&source_id), ) else { - return; + return Ok(()); }; let Some(range) = span_to_lsp_range(source, span) else { - return; + return Ok(()); }; - reporter.entry(url).push(report(range, error)); + reporter.entry(url).try_push(report(range, error)?)?; + Ok(()) } /// Convert the given span and error into an error diagnostic. @@ -760,21 +809,23 @@ fn report_without_span( source_id: SourceId, error: E, report: R, -) where +) -> Result<()> +where E: fmt::Display, - R: Fn(lsp::Range, E) -> lsp::Diagnostic, + R: Fn(lsp::Range, E) -> alloc::Result, { let Some(url) = build.id_to_url.get(&source_id) else { - return; + return Ok(()); }; let range = lsp::Range::default(); let diagnostics = reporter.entry(url); - diagnostics.push(report(range, error)); + diagnostics.try_push(report(range, error)?)?; + Ok(()) } /// Convert the given span and error into an error diagnostic. -fn to_error(range: lsp::Range, error: E) -> lsp::Diagnostic +fn to_error(range: lsp::Range, error: E) -> alloc::Result where E: fmt::Display, { @@ -782,7 +833,7 @@ where } /// Convert the given span and error into a warning diagnostic. -fn to_warning(range: lsp::Range, error: E) -> lsp::Diagnostic +fn to_warning(range: lsp::Range, error: E) -> alloc::Result where E: fmt::Display, { @@ -794,21 +845,21 @@ fn display_to_diagnostic( range: lsp::Range, error: E, severity: lsp::DiagnosticSeverity, -) -> lsp::Diagnostic +) -> alloc::Result where E: fmt::Display, { - lsp::Diagnostic { + Ok(lsp::Diagnostic { range, severity: Some(severity), code: None, code_description: None, source: None, - message: error.to_string(), + message: error.try_to_string()?.into_std(), related_information: None, tags: None, data: None, - } + }) } #[derive(Default)] @@ -818,7 +869,7 @@ pub(super) struct Index { } /// A definition source. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(super) enum DefinitionSource { /// Only a file source. Source(SourceId), @@ -853,7 +904,7 @@ impl DefinitionSource { } } -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(super) struct Definition { /// The kind of the definition. pub(super) kind: DefinitionKind, @@ -861,7 +912,8 @@ pub(super) struct Definition { pub(super) source: DefinitionSource, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(super) enum DefinitionKind { /// A unit struct. EmptyStruct, @@ -900,10 +952,9 @@ impl Visitor { } impl CompileVisitor for Visitor { - fn visit_meta(&mut self, location: &dyn Located, meta: MetaRef<'_>) { - let source = match meta.source { - Some(source) => source, - None => return, + fn visit_meta(&mut self, location: &dyn Located, meta: MetaRef<'_>) -> Result<(), MetaError> { + let Some(source) = meta.source else { + return Ok(()); }; let kind = match &meta.kind { @@ -939,21 +990,23 @@ impl CompileVisitor for Visitor { associated: Some(..), .. } => DefinitionKind::AssociatedFunction, - _ => return, + _ => return Ok(()), }; let definition = Definition { kind, - source: DefinitionSource::SourceMeta(source.clone()), + source: DefinitionSource::SourceMeta(source.try_clone()?), }; let location = location.location(); - let index = self.indexes.entry(location.source_id).or_default(); + let index = self.indexes.entry(location.source_id).or_try_default()?; if let Some(d) = index.definitions.insert(location.span, definition) { tracing::warn!("Replaced definition: {:?}", d.kind) } + + Ok(()) } fn visit_variable_use( @@ -961,20 +1014,22 @@ impl CompileVisitor for Visitor { source_id: SourceId, var_span: &dyn Spanned, span: &dyn Spanned, - ) { + ) -> Result<(), MetaError> { let definition = Definition { kind: DefinitionKind::Local, source: DefinitionSource::Location(Location::new(source_id, var_span.span())), }; - let index = self.indexes.entry(source_id).or_default(); + let index = self.indexes.entry(source_id).or_try_default()?; if let Some(d) = index.definitions.insert(span.span(), definition) { tracing::warn!("replaced definition: {:?}", d.kind) } + + Ok(()) } - fn visit_mod(&mut self, location: &dyn Located) { + fn visit_mod(&mut self, location: &dyn Located) -> Result<(), MetaError> { let location = location.location(); let definition = Definition { @@ -982,11 +1037,13 @@ impl CompileVisitor for Visitor { source: DefinitionSource::Source(location.source_id), }; - let index = self.indexes.entry(location.source_id).or_default(); + let index = self.indexes.entry(location.source_id).or_try_default()?; if let Some(d) = index.definitions.insert(location.span, definition) { tracing::warn!("replaced definition: {:?}", d.kind) } + + Ok(()) } } @@ -1005,30 +1062,36 @@ impl<'a> ScriptSourceLoader<'a> { } /// Generate a collection of URl candidates. - fn candidates(root: &Path, item: &Item) -> Option<[(Url, PathBuf); 2]> { - let mut base = root.to_owned(); + fn candidates( + root: &Path, + item: &Item, + span: &dyn Spanned, + ) -> compile::Result> { + let mut base = root.try_to_owned()?; let mut it = item.iter().peekable(); let mut last = None; while let Some(c) = it.next() { if it.peek().is_none() { - last = match c { - ComponentRef::Str(string) => Some(string), - _ => return None, + let ComponentRef::Str(string) = c else { + return Ok(None); }; + last = Some(string); break; } - if let ComponentRef::Str(string) = c { - base.push(string); - } else { - return None; - } + let ComponentRef::Str(string) = c else { + return Ok(None); + }; + + base.push(string); } - let last = last?; + let Some(last) = last else { + return Ok(None); + }; let mut a = base.clone(); a.push(&format!("{}.rn", last)); @@ -1037,10 +1100,10 @@ impl<'a> ScriptSourceLoader<'a> { b.push(last); b.push("mod.rn"); - let a_url = crate::languageserver::url::from_file_path(&a).ok()?; - let b_url = crate::languageserver::url::from_file_path(&b).ok()?; + let a_url = crate::languageserver::url::from_file_path(&a).with_span(span)?; + let b_url = crate::languageserver::url::from_file_path(&b).with_span(span)?; - Some([(a_url, a), (b_url, b)]) + Ok(Some([(a_url, a), (b_url, b)])) } } @@ -1053,10 +1116,10 @@ impl<'a> crate::compile::SourceLoader for ScriptSourceLoader<'a> { ) -> compile::Result { tracing::trace!("load {} (root: {})", item, root.display()); - if let Some(candidates) = Self::candidates(root, item) { + if let Some(candidates) = Self::candidates(root, item, span)? { for (url, path) in candidates { if let Some(s) = self.sources.get(&url) { - return Ok(crate::Source::with_path(url, s.to_string(), path)); + return Ok(crate::Source::with_path(url, s.try_to_string()?, path)); } } } @@ -1084,7 +1147,8 @@ impl<'a> workspace::SourceLoader for WorkspaceSourceLoader<'a> { fn load(&mut self, span: Span, path: &Path) -> Result { if let Ok(url) = crate::languageserver::url::from_file_path(path) { if let Some(s) = self.sources.get(&url) { - return Ok(crate::Source::with_path(url, s.to_string(), path)); + let source = s.try_to_string().with_span(span)?; + return Ok(crate::Source::with_path(url, source, path)); } } diff --git a/crates/rune/src/languageserver/url.rs b/crates/rune/src/languageserver/url.rs index 215fc4ef2..0202b75c0 100644 --- a/crates/rune/src/languageserver/url.rs +++ b/crates/rune/src/languageserver/url.rs @@ -1,8 +1,12 @@ // Implementation copied and adjusted from https://github.com/servo/rust-url -use crate::no_std::prelude::*; +use std::fmt::Write; +use std::path::Path; + +use anyhow::anyhow; -use std::{fmt::Write, path::Path}; +use crate::no_std::prelude::*; +use crate::support::Result; use percent_encoding::{percent_encode, AsciiSet, CONTROLS}; use url::Url; @@ -14,13 +18,17 @@ const PATH: &AsciiSet = &FRAGMENT.add(b'#').add(b'?').add(b'{').add(b'}'); const PATH_SEGMENT: &AsciiSet = &PATH.add(b'/').add(b'%'); /// Convert a file path into a URL. -pub(super) fn from_file_path

(path: P) -> Result +pub(super) fn from_file_path

(path: P) -> Result where P: AsRef, { let mut buf = "file://".to_owned(); - path_to_file_url_segments(path.as_ref(), &mut buf)?; - Url::parse(&buf).map_err(|_| ()) + + let Ok(()) = path_to_file_url_segments(path.as_ref(), &mut buf) else { + return Err(anyhow!("failed to construct file segments")); + }; + + Ok(Url::parse(&buf)?) } #[cfg(any(unix, target_os = "redox", target_os = "wasi"))] diff --git a/crates/rune/src/lib.rs b/crates/rune/src/lib.rs index fe568a15e..5b02f14a3 100644 --- a/crates/rune/src/lib.rs +++ b/crates/rune/src/lib.rs @@ -80,9 +80,9 @@ //! use std::sync::Arc; //! //! #[tokio::main] -//! async fn main() -> rune::Result<()> { +//! async fn main() -> rune::support::Result<()> { //! let context = Context::with_default_modules()?; -//! let runtime = Arc::new(context.runtime()); +//! let runtime = Arc::new(context.runtime()?); //! //! let mut sources = Sources::new(); //! sources.insert(Source::new( @@ -185,13 +185,7 @@ macro_rules! span { }; } -/// Exported result type for convenience using [anyhow::Error] as the default -/// error type. -pub type Result = ::core::result::Result; - -/// Boxed error type, which is an alias of [anyhow::Error]. -pub type Error = crate::no_std::Error; - +#[doc(inline)] pub use rune_alloc as alloc; #[macro_use] @@ -270,6 +264,9 @@ pub use self::sources::{SourceId, Sources}; mod worker; +#[doc(hidden)] +pub mod support; + cfg_workspace! { pub mod workspace; } @@ -397,14 +394,14 @@ pub(crate) use rune_macros::__internal_impl_any; /// /// ```rust /// # use rune::Any; -/// # use rune::runtime::Formatter; +/// # use rune::runtime::{Formatter, VmResult}; /// #[derive(Any)] /// struct Struct { /// /* .. */ /// } /// /// #[rune::function(instance, protocol = STRING_DISPLAY)] -/// fn string_display(this: &Struct, f: &mut Formatter) -> std::fmt::Result { +/// fn string_display(this: &Struct, f: &mut Formatter) -> VmResult<()> { /// /* .. */ /// # todo!() /// } @@ -461,7 +458,7 @@ pub(crate) use rune_macros::__internal_impl_any; /// use rune::{Any, Module, ContextError}; /// use rune::vm_write; /// use rune::runtime::{Formatter, VmResult}; -/// use rune::alloc::TryWrite; +/// use rune::alloc::fmt::TryWrite; /// /// #[derive(Any)] /// struct String { @@ -548,6 +545,43 @@ pub(crate) use rune_macros::__internal_impl_any; /// Ok(m) /// } /// ``` +/// +/// # Using `vm_result` and `.vm?`. +/// +/// In order to conveniently deal with virtual machine errors which require use +/// [`VmResult`] this attribute macro supports the `vm_result` option. +/// +/// This changes the return value of the function to be [`VmResult`], and +/// ensures that any try operator use is wrapped as appropriate. The special +/// operator `.vm?` is also supported in this context, which is a +/// shorthand for the [`vm_try!`] macro. +/// +/// ``` +/// use rune::alloc::String; +/// use rune::alloc::prelude::*; +/// +/// #[rune::function(vm_result)] +/// fn trim(string: &str) -> String { +/// string.trim().try_to_owned().vm? +/// } +/// ``` +/// +/// This can be combined with regular uses of the try operator `?`: +/// +/// ``` +/// use core::str::Utf8Error; +/// +/// use rune::alloc::String; +/// use rune::alloc::prelude::*; +/// +/// #[rune::function(vm_result)] +/// fn trim_bytes(bytes: &[u8]) -> Result { +/// Ok(core::str::from_utf8(bytes)?.trim().try_to_owned().vm?) +/// } +/// ``` +/// +/// [`VmResult`]: crate::runtime::VmResult +/// [`vm_try!`]: crate::vm_try! pub use rune_macros::function; /// Macro used to annotate native functions which can be loaded as macros in diff --git a/crates/rune/src/macros.rs b/crates/rune/src/macros.rs index c17b38570..dcd43bfd3 100644 --- a/crates/rune/src/macros.rs +++ b/crates/rune/src/macros.rs @@ -17,6 +17,7 @@ //! use rune::macros::{quote, MacroContext, TokenStream, ToTokens}; //! use rune::parse::Parser; //! use rune::termcolor::{ColorChoice, StandardStream}; +//! use rune::alloc::String; //! //! use std::sync::Arc; //! @@ -27,7 +28,7 @@ //! let mut p = Parser::from_token_stream(input, cx.input_span()); //! //! let ident = p.parse::()?; -//! output.push_str(cx.resolve(ident)?); +//! output.try_push_str(cx.resolve(ident)?)?; //! //! while p.parse::>()?.is_some() { //! if p.is_eof()? { @@ -35,13 +36,13 @@ //! } //! //! let ident = p.parse::()?; -//! output.push_str(cx.resolve(ident)?); +//! output.try_push_str(cx.resolve(ident)?)?; //! } //! //! p.eof()?; //! -//! let output = cx.ident(&output); -//! Ok(quote!(#output).into_token_stream(cx)) +//! let output = cx.ident(&output)?; +//! Ok(quote!(#output).into_token_stream(cx)?) //! } //! //! #[rune::attribute_macro] @@ -64,7 +65,7 @@ //! let mut context = Context::new(); //! context.install(m)?; //! -//! let runtime = Arc::new(context.runtime()); +//! let runtime = Arc::new(context.runtime()?); //! //! let mut sources = rune::sources! { //! entry => { @@ -100,7 +101,7 @@ //! let value: u32 = rune::from_value(value)?; //! //! assert_eq!(value, 42); -//! # Ok::<_, rune::Error>(()) +//! # Ok::<_, rune::support::Error>(()) //! ``` mod format_args; @@ -114,6 +115,8 @@ mod token_stream; pub use self::format_args::FormatArgs; pub use self::into_lit::IntoLit; pub(crate) use self::macro_compiler::MacroCompiler; +#[cfg(feature = "std")] +pub use self::macro_context::test; pub use self::macro_context::MacroContext; pub use self::quote_fn::{quote_fn, Quote}; pub(crate) use self::storage::Storage; diff --git a/crates/rune/src/macros/format_args.rs b/crates/rune/src/macros/format_args.rs index a3462b79a..caa748c61 100644 --- a/crates/rune/src/macros/format_args.rs +++ b/crates/rune/src/macros/format_args.rs @@ -1,19 +1,15 @@ use core::str; -use crate::no_std::collections::{BTreeMap, BTreeSet, HashMap}; -use crate::no_std::prelude::*; - -use crate::ast; -use crate::ast::{Span, Spanned}; +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, BTreeMap, BTreeSet, Box, HashMap, String, Vec}; +use crate::ast::{self, Span, Spanned}; use crate::compile::ir; use crate::compile::{self, WithSpan}; use crate::macros::{quote, MacroContext, Quote}; use crate::parse::{Parse, Parser, Peek, Peeker}; use crate::runtime::format; -// NB: needed for quote macro. -use crate as rune; - /// A format specification: A format string followed by arguments to be /// formatted in accordance with that string. /// @@ -44,11 +40,11 @@ impl FormatArgs { )); } - pos.push(expr); + pos.try_push(expr)?; } FormatArg::Named(n) => { let name = cx.resolve(n.key)?; - named.insert(name.into(), n); + named.try_insert(name.try_into()?, n)?; } } } @@ -63,11 +59,11 @@ impl FormatArgs { } }; - let mut unused_pos = (0..pos.len()).collect::>(); + let mut unused_pos = (0..pos.len()).try_collect::>()?; let mut unused_named = named .iter() - .map(|(key, n)| (key.clone(), n.span())) - .collect::>(); + .map(|(key, n)| Ok::<_, alloc::Error>((key.try_clone()?, n.span()))) + .try_collect::>>()??; let expanded = match expand_format_spec( cx, @@ -121,7 +117,7 @@ impl Parse for FormatArgs { break; } - args.push(p.parse()?); + args.try_push(p.parse()?)?; } Ok(Self { format, args }) @@ -135,7 +131,7 @@ impl Peek for FormatArgs { } /// A named format argument. -#[derive(Debug, Clone, Parse, Spanned)] +#[derive(Debug, TryClone, Parse, Spanned)] pub struct NamedFormatArg { /// The key of the named argument. pub key: ast::Ident, @@ -146,7 +142,7 @@ pub struct NamedFormatArg { } /// A single format argument. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub enum FormatArg { /// A positional argument. Positional(ast::Expr), @@ -186,11 +182,11 @@ fn expand_format_spec<'a>( while let Some(value) = iter.next() { match value { ('}', '}') => { - buf.push('}'); + buf.try_push('}')?; iter.next(); } ('{', '{') => { - buf.push('{'); + buf.try_push('{')?; iter.next(); } ('}', _) => { @@ -201,11 +197,11 @@ fn expand_format_spec<'a>( } ('{', _) => { if !buf.is_empty() { - components.push(C::Literal(buf.clone().into_boxed_str())); + components.try_push(C::Literal(buf.try_clone()?.try_into_boxed_str()?))?; buf.clear(); } - components.push(parse_group( + components.try_push(parse_group( cx, span, &mut iter, @@ -217,16 +213,16 @@ fn expand_format_spec<'a>( unused_pos, named, unused_named, - )?); + )?)?; } (a, _) => { - buf.push(a); + buf.try_push(a)?; } } } if !buf.is_empty() { - components.push(C::Literal(buf.clone().into_boxed_str())); + components.try_push(C::Literal(buf.try_clone()?.try_into_boxed_str()?))?; buf.clear(); } @@ -239,8 +235,8 @@ fn expand_format_spec<'a>( for c in components { match c { C::Literal(literal) => { - let lit = cx.lit(&*literal); - args.push(quote!(#lit)); + let lit = cx.lit(&*literal)?; + args.try_push(quote!(#lit))?; } C::Format { expr, @@ -253,43 +249,62 @@ fn expand_format_spec<'a>( } => { let mut specs = Vec::new(); - specs.extend(fill.map(|fill| { - let fill = cx.lit(fill); - quote!(fill = #fill) - })); - - specs.extend(width.map(|width| { - let width = cx.lit(width); - quote!(width = #width) - })); - - specs.extend(precision.map(|precision| { - let precision = cx.lit(precision); - quote!(precision = #precision) - })); - - specs.extend(align.map(|align| { - let align = cx.ident(&align.to_string()); - quote!(align = #align) - })); + let fill = fill + .map(|fill| { + let fill = cx.lit(fill)?; + Ok::<_, alloc::Error>(quote!(fill = #fill)) + }) + .transpose()?; + + let width = width + .map(|width| { + let width = cx.lit(width)?; + Ok::<_, alloc::Error>(quote!(width = #width)) + }) + .transpose()?; + + let precision = precision + .map(|precision| { + let precision = cx.lit(precision)?; + Ok::<_, alloc::Error>(quote!(precision = #precision)) + }) + .transpose()?; + + let align = align + .map(|align| { + let align = align.try_to_string()?; + let align = cx.ident(&align)?; + Ok::<_, alloc::Error>(quote!(align = #align)) + }) + .transpose()?; + + specs.try_extend(fill)?; + specs.try_extend(width)?; + specs.try_extend(precision)?; + specs.try_extend(align)?; if !flags.is_empty() { - let flags = cx.lit(flags.into_u32()); - specs.push(quote!(flags = #flags)); + let flags = cx.lit(flags.into_u32())?; + specs.try_push(quote!(flags = #flags))?; } - specs.extend(format_type.map(|format_type| { - let format_type = cx.ident(&format_type.to_string()); - quote!(type = #format_type) - })); + let format_type = format_type + .map(|format_type| { + let format_type = format_type.try_to_string()?; + let format_type = cx.ident(&format_type)?; + Ok::<_, alloc::Error>(quote!(type = #format_type)) + }) + .transpose()?; + + specs.try_extend(format_type)?; if specs.is_empty() { - args.push(quote!(#expr)); + args.try_push(quote!(#expr))?; } else { - args.push(quote!( + args.try_push(quote!( #[builtin] format!(#expr, #(specs),*) - )); + ))?; } } } @@ -386,7 +401,7 @@ fn expand_format_spec<'a>( mode = Mode::End; } c => { - name.push(c); + name.try_push(c)?; iter.next(); } }, @@ -439,7 +454,7 @@ fn expand_format_spec<'a>( Mode::Width => { match a { '0'..='9' => { - width.push(a); + width.try_push(a)?; iter.next(); continue; } @@ -460,7 +475,7 @@ fn expand_format_spec<'a>( iter.next(); } '0'..='9' => { - precision.push(a); + precision.try_push(a)?; iter.next(); continue; } diff --git a/crates/rune/src/macros/into_lit.rs b/crates/rune/src/macros/into_lit.rs index 50a410b41..1dfbb9d5b 100644 --- a/crates/rune/src/macros/into_lit.rs +++ b/crates/rune/src/macros/into_lit.rs @@ -1,85 +1,84 @@ -use crate::no_std::prelude::*; - +use crate::alloc::{self, String}; use crate::ast; use crate::macros::MacroContext; /// Helper trait used for things that can be converted into tokens. pub trait IntoLit { /// Convert the current thing into a token. - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit; + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result; } impl IntoLit for T where ast::Number: From, { - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit { + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result { let span = cx.macro_span(); - let id = cx.idx.q.storage.insert_number(self); + let id = cx.idx.q.storage.insert_number(self)?; let source = ast::NumberSource::Synthetic(id); - ast::Lit::Number(ast::LitNumber { span, source }) + Ok(ast::Lit::Number(ast::LitNumber { span, source })) } } impl IntoLit for char { - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit { + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result { let span = cx.macro_span(); let source = ast::CopySource::Inline(self); - ast::Lit::Char(ast::LitChar { span, source }) + Ok(ast::Lit::Char(ast::LitChar { span, source })) } } impl IntoLit for u8 { - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit { + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result { let span = cx.macro_span(); let source = ast::CopySource::Inline(self); - ast::Lit::Byte(ast::LitByte { span, source }) + Ok(ast::Lit::Byte(ast::LitByte { span, source })) } } impl IntoLit for &str { - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit { + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result { let span = cx.macro_span(); - let id = cx.idx.q.storage.insert_str(self); + let id = cx.idx.q.storage.insert_str(self)?; let source = ast::StrSource::Synthetic(id); - ast::Lit::Str(ast::LitStr { span, source }) + Ok(ast::Lit::Str(ast::LitStr { span, source })) } } impl IntoLit for &String { - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit { + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result { <&str>::into_lit(self, cx) } } impl IntoLit for String { - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit { + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result { let span = cx.macro_span(); - let id = cx.idx.q.storage.insert_string(self); + let id = cx.idx.q.storage.insert_string(self)?; let source = ast::StrSource::Synthetic(id); - ast::Lit::Str(ast::LitStr { span, source }) + Ok(ast::Lit::Str(ast::LitStr { span, source })) } } impl IntoLit for &[u8] { - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit { + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result { let span = cx.macro_span(); - let id = cx.idx.q.storage.insert_byte_string(self); + let id = cx.idx.q.storage.insert_byte_string(self)?; let source = ast::StrSource::Synthetic(id); - ast::Lit::ByteStr(ast::LitByteStr { span, source }) + Ok(ast::Lit::ByteStr(ast::LitByteStr { span, source })) } } impl IntoLit for [u8; N] { #[inline] - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit { + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result { <&[u8]>::into_lit(&self[..], cx) } } impl IntoLit for &[u8; N] { #[inline] - fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> ast::Lit { + fn into_lit(self, cx: &mut MacroContext<'_, '_, '_>) -> alloc::Result { <&[u8]>::into_lit(self, cx) } } diff --git a/crates/rune/src/macros/macro_compiler.rs b/crates/rune/src/macros/macro_compiler.rs index 8cf500e99..78bcc2fa6 100644 --- a/crates/rune/src/macros/macro_compiler.rs +++ b/crates/rune/src/macros/macro_compiler.rs @@ -1,7 +1,6 @@ //! Macro compiler. -use crate::no_std::prelude::*; - +use crate::alloc::prelude::*; use crate::ast; use crate::ast::Spanned; use crate::compile::{self, ErrorKind, ItemMeta}; @@ -41,7 +40,7 @@ impl MacroCompiler<'_, '_, '_> { return Err(compile::Error::new( span, ErrorKind::MissingMacro { - item: self.idx.q.pool.item(named.item).to_owned(), + item: self.idx.q.pool.item(named.item).try_to_owned()?, }, )); } @@ -104,7 +103,7 @@ impl MacroCompiler<'_, '_, '_> { }; let mut item_stream = TokenStream::new(); - item.to_tokens(&mut macro_context, &mut item_stream); + item.to_tokens(&mut macro_context, &mut item_stream)?; handler(&mut macro_context, input_stream, &item_stream)? }; diff --git a/crates/rune/src/macros/macro_context.rs b/crates/rune/src/macros/macro_context.rs index 71be9dcbc..b7a6dec0f 100644 --- a/crates/rune/src/macros/macro_context.rs +++ b/crates/rune/src/macros/macro_context.rs @@ -2,20 +2,110 @@ use core::fmt; +use crate::alloc; use crate::ast; use crate::ast::Span; use crate::compile::ir; -use crate::compile::{ - self, Context, ErrorKind, Item, ItemMeta, NoopCompileVisitor, NoopSourceLoader, Pool, Prelude, - UnitBuilder, -}; -use crate::hir; -use crate::indexing::{IndexItem, Indexer, Items, Scopes}; -use crate::macros::{IntoLit, Storage, ToTokens, TokenStream}; +use crate::compile::{self, ErrorKind, ItemMeta}; +use crate::indexing::Indexer; +use crate::macros::{IntoLit, ToTokens, TokenStream}; use crate::parse::{Parse, Resolve}; -use crate::query::Query; -use crate::shared::{Consts, Gen}; -use crate::{Diagnostics, Options, Source, SourceId, Sources}; +use crate::{Source, SourceId}; + +/// Construct an empty macro context which can be used for testing. +/// +/// # Examples +/// +/// ``` +/// use rune::ast; +/// use rune::macros; +/// +/// macros::test(|cx| { +/// let lit = cx.lit("hello world")?; +/// assert!(matches!(lit, ast::Lit::Str(..))); +/// Ok(()) +/// })?; +/// # Ok::<_, rune::support::Error>(()) +/// ``` +#[cfg(feature = "std")] +pub fn test(f: F) -> crate::support::Result +where + F: FnOnce(&mut MacroContext<'_, '_, '_>) -> crate::support::Result, +{ + use crate::compile::{Item, NoopCompileVisitor, NoopSourceLoader, Pool, Prelude, UnitBuilder}; + use crate::hir; + use crate::indexing::{IndexItem, Items, Scopes}; + use crate::macros::Storage; + use crate::query::Query; + use crate::shared::{Consts, Gen}; + use crate::{Context, Diagnostics, Options, Sources}; + use anyhow::Context as _; + + let mut unit = UnitBuilder::default(); + let prelude = Prelude::default(); + let gen = Gen::default(); + let const_arena = hir::Arena::new(); + let mut consts = Consts::default(); + let mut storage = Storage::default(); + let mut sources = Sources::default(); + let mut pool = Pool::new().context("Failed to allocate pool")?; + let mut visitor = NoopCompileVisitor::new(); + let mut diagnostics = Diagnostics::default(); + let mut source_loader = NoopSourceLoader::default(); + let options = Options::default(); + let context = Context::default(); + let mut inner = Default::default(); + + let mut query = Query::new( + &mut unit, + &prelude, + &const_arena, + &mut consts, + &mut storage, + &mut sources, + &mut pool, + &mut visitor, + &mut diagnostics, + &mut source_loader, + &options, + &gen, + &context, + &mut inner, + ); + + let root_id = gen.next(); + let source_id = SourceId::empty(); + + let root_mod_id = query + .insert_root_mod(root_id, source_id, Span::empty()) + .context("Failed to inserted root module")?; + + let item_meta = query + .item_for(root_id) + .context("Just inserted item meta does not exist")?; + + let mut idx = Indexer { + q: query.borrow(), + source_id, + items: Items::new(Item::new(), root_id, &gen).context("Failed to construct items")?, + scopes: Scopes::new().context("Failed to build indexer scopes")?, + item: IndexItem::new(root_mod_id), + nested_item: None, + macro_depth: 0, + root: None, + queue: None, + loaded: None, + }; + + let mut cx = MacroContext { + macro_span: Span::empty(), + input_span: Span::empty(), + item_meta, + idx: &mut idx, + }; + + f(&mut cx) +} /// Context for a running macro. pub struct MacroContext<'a, 'b, 'arena> { @@ -30,85 +120,6 @@ pub struct MacroContext<'a, 'b, 'arena> { } impl<'a, 'b, 'arena> MacroContext<'a, 'b, 'arena> { - /// Construct an empty macro context which can be used for testing. - /// - /// # Examples - /// - /// ``` - /// use rune::macros::MacroContext; - /// - /// MacroContext::test(|cx| ()); - /// ``` - pub fn test(f: F) -> O - where - F: FnOnce(&mut MacroContext<'_, '_, '_>) -> O, - { - let mut unit = UnitBuilder::default(); - let prelude = Prelude::default(); - let gen = Gen::default(); - let const_arena = hir::Arena::new(); - let mut consts = Consts::default(); - let mut storage = Storage::default(); - let mut sources = Sources::default(); - let mut pool = Pool::default(); - let mut visitor = NoopCompileVisitor::new(); - let mut diagnostics = Diagnostics::default(); - let mut source_loader = NoopSourceLoader::default(); - let options = Options::default(); - let context = Context::default(); - let mut inner = Default::default(); - - let mut query = Query::new( - &mut unit, - &prelude, - &const_arena, - &mut consts, - &mut storage, - &mut sources, - &mut pool, - &mut visitor, - &mut diagnostics, - &mut source_loader, - &options, - &gen, - &context, - &mut inner, - ); - - let root_id = gen.next(); - let source_id = SourceId::empty(); - - let root_mod_id = query - .insert_root_mod(root_id, source_id, Span::empty()) - .expect("Failed to inserted root module"); - - let item_meta = query - .item_for(root_id) - .expect("Just inserted item meta does not exist"); - - let mut idx = Indexer { - q: query.borrow(), - source_id, - items: Items::new(Item::new(), root_id, &gen), - scopes: Scopes::default(), - item: IndexItem::new(root_mod_id), - nested_item: None, - macro_depth: 0, - root: None, - queue: None, - loaded: None, - }; - - let mut cx = MacroContext { - macro_span: Span::empty(), - input_span: Span::empty(), - item_meta, - idx: &mut idx, - }; - - f(&mut cx) - } - /// Evaluate the given target as a constant expression. /// /// # Panics @@ -118,20 +129,23 @@ impl<'a, 'b, 'arena> MacroContext<'a, 'b, 'arena> { /// # Examples /// /// ``` + /// # use rune::support::*; /// use rune::ast; - /// use rune::macros::{MacroContext, quote}; + /// use rune::macros::{self, quote}; /// use rune::parse::{Parser}; /// - /// // Note: should only be used for testing. - /// MacroContext::test(|cx| { - /// let stream = quote!(1 + 2).into_token_stream(cx); + /// macros::test(|cx| { + /// let stream = quote!(1 + 2).into_token_stream(cx)?; /// /// let mut p = Parser::from_token_stream(&stream, cx.input_span()); - /// let expr = p.parse_all::().unwrap(); - /// let value = cx.eval(&expr).unwrap(); + /// let expr = p.parse_all::()?; + /// let value = cx.eval(&expr)?; /// - /// assert_eq!(3, value.into_integer::().unwrap()); - /// }); + /// let integer = value.into_integer::().context("Expected integer")?; + /// assert_eq!(3, integer); + /// Ok(()) + /// })?; + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn eval(&mut self, target: &ast::Expr) -> compile::Result { target.eval(self) @@ -143,14 +157,16 @@ impl<'a, 'b, 'arena> MacroContext<'a, 'b, 'arena> { /// /// ``` /// use rune::ast; - /// use rune::macros::MacroContext; + /// use rune::macros; /// - /// MacroContext::test(|cx| { - /// let lit = cx.lit("hello world"); - /// assert!(matches!(lit, ast::Lit::Str(..))) - /// }); + /// macros::test(|cx| { + /// let lit = cx.lit("hello world")?; + /// assert!(matches!(lit, ast::Lit::Str(..))); + /// Ok(()) + /// })?; + /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn lit(&mut self, lit: T) -> ast::Lit + pub fn lit(&mut self, lit: T) -> alloc::Result where T: IntoLit, { @@ -164,18 +180,20 @@ impl<'a, 'b, 'arena> MacroContext<'a, 'b, 'arena> { /// /// ``` /// use rune::ast; - /// use rune::macros::MacroContext; + /// use rune::macros; /// - /// MacroContext::test(|cx| { - /// let lit = cx.ident("foo"); - /// assert!(matches!(lit, ast::Ident { .. })) - /// }); + /// macros::test(|cx| { + /// let lit = cx.ident("foo")?; + /// assert!(matches!(lit, ast::Ident { .. })); + /// Ok(()) + /// })?; + /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn ident(&mut self, ident: &str) -> ast::Ident { + pub fn ident(&mut self, ident: &str) -> alloc::Result { let span = self.macro_span(); - let id = self.idx.q.storage.insert_str(ident); + let id = self.idx.q.storage.insert_str(ident)?; let source = ast::LitSource::Synthetic(id); - ast::Ident { span, source } + Ok(ast::Ident { span, source }) } /// Construct a new label from the given string. The string should be @@ -188,28 +206,30 @@ impl<'a, 'b, 'arena> MacroContext<'a, 'b, 'arena> { /// /// ``` /// use rune::ast; - /// use rune::macros::MacroContext; + /// use rune::macros; /// - /// MacroContext::test(|cx| { - /// let lit = cx.label("foo"); - /// assert!(matches!(lit, ast::Label { .. })) - /// }); + /// macros::test(|cx| { + /// let lit = cx.label("foo")?; + /// assert!(matches!(lit, ast::Label { .. })); + /// Ok(()) + /// })?; + /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn label(&mut self, label: &str) -> ast::Label { + pub fn label(&mut self, label: &str) -> alloc::Result { let span = self.macro_span(); - let id = self.idx.q.storage.insert_str(label); + let id = self.idx.q.storage.insert_str(label)?; let source = ast::LitSource::Synthetic(id); - ast::Label { span, source } + Ok(ast::Label { span, source }) } /// Stringify the token stream. - pub fn stringify(&mut self, tokens: &T) -> Stringify<'_, 'a, 'b, 'arena> + pub fn stringify(&mut self, tokens: &T) -> alloc::Result> where T: ToTokens, { let mut stream = TokenStream::new(); - tokens.to_tokens(self, &mut stream); - Stringify { cx: self, stream } + tokens.to_tokens(self, &mut stream)?; + Ok(Stringify { cx: self, stream }) } /// Resolve the value of a token. @@ -232,7 +252,7 @@ impl<'a, 'b, 'arena> MacroContext<'a, 'b, 'arena> { /// Insert the given source so that it has a [SourceId] that can be used in /// combination with parsing functions such as /// [parse_source][MacroContext::parse_source]. - pub fn insert_source(&mut self, name: &str, source: &str) -> SourceId { + pub fn insert_source(&mut self, name: &str, source: &str) -> alloc::Result { self.idx.q.sources.insert(Source::new(name, source)) } diff --git a/crates/rune/src/macros/quote_fn.rs b/crates/rune/src/macros/quote_fn.rs index 4172a6f69..bb3eaaae2 100644 --- a/crates/rune/src/macros/quote_fn.rs +++ b/crates/rune/src/macros/quote_fn.rs @@ -1,21 +1,22 @@ use core::fmt; -use crate::no_std::prelude::*; - +use crate::alloc; use crate::macros::{MacroContext, ToTokens, TokenStream}; -type EncodeFn<'a> = dyn Fn(&mut MacroContext<'_, '_, '_>, &mut TokenStream) + Send + Sync + 'a; +type EncodeFn<'a> = + dyn Fn(&mut MacroContext<'_, '_, '_>, &mut TokenStream) -> alloc::Result<()> + Send + Sync + 'a; /// Construct a token stream from a function. pub fn quote_fn<'a, T>(f: T) -> Quote<'a> where - T: 'a + Fn(&mut MacroContext<'_, '_, '_>, &mut TokenStream) + Send + Sync, + T: 'a + Fn(&mut MacroContext<'_, '_, '_>, &mut TokenStream) -> alloc::Result<()> + Send + Sync, { - Quote(Box::new(f)) + // TODO: somehow support CoerceUnsized. + Quote(rust_alloc::boxed::Box::new(f)) } /// [ToTokens] implementation generated by [quote_fn]. -pub struct Quote<'a>(Box>); +pub struct Quote<'a>(rust_alloc::boxed::Box>); impl<'a> Quote<'a> { /// Convert into token stream. @@ -23,15 +24,22 @@ impl<'a> Quote<'a> { /// # Panics /// /// This panics if called outside of a macro context. - pub fn into_token_stream(self, cx: &mut MacroContext<'_, '_, '_>) -> TokenStream { + pub fn into_token_stream( + self, + cx: &mut MacroContext<'_, '_, '_>, + ) -> alloc::Result { let mut stream = TokenStream::new(); - self.to_tokens(cx, &mut stream); - stream + self.to_tokens(cx, &mut stream)?; + Ok(stream) } } impl<'a> ToTokens for Quote<'a> { - fn to_tokens(&self, context: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + context: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { (self.0)(context, stream) } } diff --git a/crates/rune/src/macros/storage.rs b/crates/rune/src/macros/storage.rs index f5a33cb2d..be2fc11f5 100644 --- a/crates/rune/src/macros/storage.rs +++ b/crates/rune/src/macros/storage.rs @@ -1,12 +1,14 @@ use core::fmt; -use crate::no_std::prelude::*; - +use crate as rune; +use crate::alloc; +use crate::alloc::prelude::*; +use crate::alloc::{HashMap, String, Vec}; use crate::ast; -use crate::no_std::collections::HashMap; /// A synthetic identifier which can be used to reference something in storage. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[try_clone(copy)] pub struct SyntheticId(usize); impl fmt::Display for SyntheticId { @@ -63,59 +65,60 @@ impl Storage { /// /// The number will be stored in this storage, and will be synthetic /// (rather than from the source). - pub(crate) fn insert_number(&mut self, number: N) -> SyntheticId + pub(crate) fn insert_number(&mut self, number: N) -> alloc::Result where ast::Number: From, { let id = SyntheticId(self.numbers.len()); - self.numbers.push(number.into()); - id + self.numbers.try_push(number.into())?; + Ok(id) } /// Insert the given text into storage and return its id. /// /// This will reuse old storage slots that already contains the given /// string. - pub(crate) fn insert_str(&mut self, string: &str) -> SyntheticId { + pub(crate) fn insert_str(&mut self, string: &str) -> alloc::Result { if let Some(id) = self.strings_rev.get(string).copied() { - return id; + return Ok(id); } let id = SyntheticId(self.strings.len()); - let string = string.to_owned(); - self.strings.push(string.clone()); - self.strings_rev.insert(string, id); - id + let string = string.try_to_owned()?; + self.strings.try_push(string.try_clone()?)?; + self.strings_rev.try_insert(string, id)?; + Ok(id) } /// Insert the given owned string into storage and return its id. /// /// This will reuse old storage slots that already contains the given /// string. - pub(crate) fn insert_string(&mut self, string: String) -> SyntheticId { + pub(crate) fn insert_string(&mut self, string: String) -> alloc::Result { if let Some(id) = self.strings_rev.get(&string).copied() { - return id; + return Ok(id); } let id = SyntheticId(self.strings.len()); - self.strings.push(string.clone()); - self.strings_rev.insert(string, id); - id + self.strings.try_push(string.try_clone()?)?; + self.strings_rev.try_insert(string, id)?; + Ok(id) } /// Insert the given text into storage and return its id. /// /// This will reuse old storage slots that already contains the given /// byte string. - pub(crate) fn insert_byte_string(&mut self, bytes: &[u8]) -> SyntheticId { + pub(crate) fn insert_byte_string(&mut self, bytes: &[u8]) -> alloc::Result { if let Some(id) = self.byte_strings_rev.get(bytes).copied() { - return id; + return Ok(id); } let id = SyntheticId(self.byte_strings.len()); - self.byte_strings.push(bytes.to_vec()); - self.byte_strings_rev.insert(bytes.to_vec(), id); - id + self.byte_strings.try_push(Vec::try_from(bytes)?)?; + self.byte_strings_rev + .try_insert(Vec::try_from(bytes)?, id)?; + Ok(id) } /// Get the content of the string with the specified id. diff --git a/crates/rune/src/macros/token_stream.rs b/crates/rune/src/macros/token_stream.rs index 948d3fcab..0a941a243 100644 --- a/crates/rune/src/macros/token_stream.rs +++ b/crates/rune/src/macros/token_stream.rs @@ -2,16 +2,18 @@ use core::fmt; use core::slice; use crate::compile; -use crate::no_std::prelude::*; -use crate::no_std::vec; +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::vec::{self, Vec}; +use crate::alloc::{self, Box}; use crate::ast; use crate::ast::{OptionSpanned, Span}; use crate::macros::MacroContext; use crate::parse::{Parse, Parser}; /// A token stream. -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, TryClone, PartialEq, Eq, Default)] pub struct TokenStream { stream: Vec, } @@ -23,17 +25,20 @@ impl TokenStream { } /// Push the current token to the stream. - pub fn push(&mut self, token: ast::Token) { - self.stream.push(token); + pub fn push(&mut self, token: ast::Token) -> alloc::Result<()> { + self.stream.try_push(token)?; + Ok(()) } /// Extend the token stream with another iterator. - pub fn extend(&mut self, tokens: I) + pub fn extend(&mut self, tokens: I) -> alloc::Result<()> where I: IntoIterator, ast::Token: From, { - self.stream.extend(tokens.into_iter().map(ast::Token::from)); + self.stream + .try_extend(tokens.into_iter().map(ast::Token::from))?; + Ok(()) } /// Create an iterator over the token stream. @@ -116,25 +121,37 @@ impl IntoIterator for TokenStream { } /// Trait for things that can be turned into tokens. -pub trait ToTokens: Sized { +pub trait ToTokens { /// Turn the current item into tokens. - fn to_tokens(&self, context: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream); + fn to_tokens( + &self, + context: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()>; } impl ToTokens for Box where T: ToTokens, { - fn to_tokens(&self, context: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { - (**self).to_tokens(context, stream); + fn to_tokens( + &self, + context: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { + (**self).to_tokens(context, stream) } } impl ToTokens for &T where - T: ToTokens, + T: ?Sized + ToTokens, { - fn to_tokens(&self, context: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + context: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { ToTokens::to_tokens(*self, context, stream) } } @@ -143,10 +160,16 @@ impl ToTokens for Option where T: ToTokens, { - fn to_tokens(&self, context: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + context: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { if let Some(this) = self { - this.to_tokens(context, stream); + this.to_tokens(context, stream)?; } + + Ok(()) } } @@ -154,10 +177,16 @@ impl ToTokens for Vec where T: ToTokens, { - fn to_tokens(&self, context: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { + fn to_tokens( + &self, + context: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { for item in self { - item.to_tokens(context, stream); + item.to_tokens(context, stream)?; } + + Ok(()) } } @@ -166,9 +195,14 @@ where A: ToTokens, B: ToTokens, { - fn to_tokens(&self, context: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { - self.0.to_tokens(context, stream); - self.1.to_tokens(context, stream); + fn to_tokens( + &self, + context: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { + self.0.to_tokens(context, stream)?; + self.1.to_tokens(context, stream)?; + Ok(()) } } @@ -178,16 +212,25 @@ where B: ToTokens, C: ToTokens, { - fn to_tokens(&self, context: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { - self.0.to_tokens(context, stream); - self.1.to_tokens(context, stream); - self.2.to_tokens(context, stream); + fn to_tokens( + &self, + context: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { + self.0.to_tokens(context, stream)?; + self.1.to_tokens(context, stream)?; + self.2.to_tokens(context, stream)?; + Ok(()) } } impl ToTokens for TokenStream { - fn to_tokens(&self, context: &mut MacroContext<'_, '_, '_>, stream: &mut TokenStream) { - self.stream.to_tokens(context, stream); + fn to_tokens( + &self, + context: &mut MacroContext<'_, '_, '_>, + stream: &mut TokenStream, + ) -> alloc::Result<()> { + self.stream.to_tokens(context, stream) } } diff --git a/crates/rune/src/module.rs b/crates/rune/src/module.rs index 17085b4c3..ad808ebe4 100644 --- a/crates/rune/src/module.rs +++ b/crates/rune/src/module.rs @@ -10,9 +10,13 @@ pub(crate) mod module; use core::fmt; use core::marker::PhantomData; -use crate::no_std::prelude::*; use crate::no_std::sync::Arc; +use crate as rune; +use crate::alloc::prelude::*; +#[cfg(feature = "doc")] +use crate::alloc::Box; +use crate::alloc::{self, Vec}; use crate::compile::{meta, ContextError, Docs, IntoComponent, Item, ItemBuf}; use crate::runtime::{ AttributeMacroHandler, ConstValue, FullTypeOf, FunctionHandler, MacroHandler, MaybeTypeOf, @@ -53,18 +57,22 @@ pub(crate) struct InternalEnum { impl InternalEnum { /// Construct a new handler for an internal enum. - fn new(name: &'static str, base_type: N, static_type: &'static StaticType) -> Self + fn new( + name: &'static str, + base_type: N, + static_type: &'static StaticType, + ) -> alloc::Result where N: IntoIterator, N::Item: IntoComponent, { - InternalEnum { + Ok(InternalEnum { name, - base_type: ItemBuf::with_item(base_type), + base_type: ItemBuf::with_item(base_type)?, static_type, variants: Vec::new(), docs: Docs::EMPTY, - } + }) } /// Register a new variant. @@ -73,23 +81,23 @@ impl InternalEnum { name: &'static str, type_check: TypeCheck, constructor: C, - ) -> ItemMut<'_> + ) -> alloc::Result> where C: Function, { let constructor: Arc = Arc::new(move |stack, args| constructor.fn_call(stack, args)); - self.variants.push(Variant { + self.variants.try_push(Variant { name, type_check: Some(type_check), fields: Some(Fields::Unnamed(C::args())), constructor: Some(constructor), docs: Docs::EMPTY, - }); + })?; let v = self.variants.last_mut().unwrap(); - ItemMut { docs: &mut v.docs } + Ok(ItemMut { docs: &mut v.docs }) } } @@ -173,7 +181,7 @@ pub(crate) enum TypeSpecification { } /// A key that identifies an associated function. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, TryClone, PartialEq, Eq, Hash)] #[non_exhaustive] pub(crate) struct AssociatedKey { /// The type the associated function belongs to. @@ -184,7 +192,7 @@ pub(crate) struct AssociatedKey { pub(crate) parameters: Hash, } -#[derive(Clone)] +#[derive(TryClone)] pub(crate) struct ModuleFunction { pub(crate) item: ItemBuf, pub(crate) handler: Arc, @@ -201,7 +209,7 @@ pub(crate) struct ModuleFunction { pub(crate) docs: Docs, } -#[derive(Clone)] +#[derive(TryClone)] pub(crate) struct ModuleAssociated { pub(crate) container: FullTypeOf, pub(crate) container_type_info: TypeInfo, @@ -251,21 +259,21 @@ impl ItemMut<'_> { /// Set documentation for an inserted item. /// /// This completely replaces any existing documentation. - pub fn docs(self, docs: I) -> Self + pub fn docs(self, docs: I) -> Result where I: IntoIterator, I::Item: AsRef, { - self.docs.set_docs(docs); - self + self.docs.set_docs(docs)?; + Ok(self) } /// Set static documentation. /// /// This completely replaces any existing documentation. - pub fn static_docs(self, docs: &'static [&'static str]) -> Self { - self.docs.set_docs(docs); - self + pub fn static_docs(self, docs: &'static [&'static str]) -> Result { + self.docs.set_docs(docs)?; + Ok(self) } } @@ -307,13 +315,13 @@ impl ItemFnMut<'_> { /// Set documentation for an inserted item. /// /// This completely replaces any existing documentation. - pub fn docs(self, docs: I) -> Self + pub fn docs(self, docs: I) -> Result where I: IntoIterator, I::Item: AsRef, { - self.docs.set_docs(docs); - self + self.docs.set_docs(docs)?; + Ok(self) } /// Mark the given item as an async function. @@ -330,16 +338,16 @@ impl ItemFnMut<'_> { pub fn deprecated( self, #[cfg_attr(not(feature = "doc"), allow(unused))] deprecated: S, - ) -> Self + ) -> Result where S: AsRef, { #[cfg(feature = "doc")] { - *self.deprecated = Some(deprecated.as_ref().into()); + *self.deprecated = Some(deprecated.as_ref().try_into()?); } - self + Ok(self) } /// Indicate the number of arguments this function accepts. @@ -369,13 +377,13 @@ impl ItemFnMut<'_> { pub fn argument_types( self, #[cfg_attr(not(feature = "doc"), allow(unused))] arguments: [Option; N], - ) -> Self { + ) -> Result { #[cfg(feature = "doc")] { - *self.argument_types = Box::from(arguments.into_iter().collect::>()); + *self.argument_types = arguments.into_iter().try_collect::>()?; } - self + Ok(self) } } @@ -406,21 +414,21 @@ where /// Set documentation for an inserted type. /// /// This completely replaces any existing documentation. - pub fn docs(self, docs: I) -> Self + pub fn docs(self, docs: I) -> Result where I: IntoIterator, I::Item: AsRef, { - self.docs.set_docs(docs); - self + self.docs.set_docs(docs)?; + Ok(self) } /// Set static documentation. /// /// This completely replaces any existing documentation. - pub fn static_docs(self, docs: &'static [&'static str]) -> Self { - self.docs.set_docs(docs); - self + pub fn static_docs(self, docs: &'static [&'static str]) -> Result { + self.docs.set_docs(docs)?; + Ok(self) } /// Mark the given variant with named fields. @@ -488,21 +496,21 @@ where /// Set documentation for an inserted type. /// /// This completely replaces any existing documentation. - pub fn docs(self, docs: I) -> Self + pub fn docs(self, docs: I) -> Result where I: IntoIterator, I::Item: AsRef, { - self.docs.set_docs(docs); - self + self.docs.set_docs(docs)?; + Ok(self) } /// Set static documentation. /// /// This completely replaces any existing documentation. - pub fn static_docs(self, docs: &'static [&'static str]) -> Self { - self.docs.set_docs(docs); - self + pub fn static_docs(self, docs: &'static [&'static str]) -> Result { + self.docs.set_docs(docs)?; + Ok(self) } /// Get the given variant mutably. @@ -540,21 +548,21 @@ where /// Set documentation for an inserted internal enum. /// /// This completely replaces any existing documentation. - pub fn docs(self, docs: I) -> Self + pub fn docs(self, docs: I) -> Result where I: IntoIterator, I::Item: AsRef, { - self.enum_.docs.set_docs(docs); - self + self.enum_.docs.set_docs(docs)?; + Ok(self) } /// Set static documentation for an inserted internal enum. /// /// This completely replaces any existing documentation. - pub fn static_docs(self, docs: &'static [&'static str]) -> Self { - self.enum_.docs.set_docs(docs); - self + pub fn static_docs(self, docs: &'static [&'static str]) -> Result { + self.enum_.docs.set_docs(docs)?; + Ok(self) } /// Get the given variant mutably. @@ -601,21 +609,21 @@ where /// Set documentation for an inserted type. /// /// This completely replaces any existing documentation. - pub fn docs(self, docs: I) -> Self + pub fn docs(self, docs: I) -> Result where I: IntoIterator, I::Item: AsRef, { - self.docs.set_docs(docs); - self + self.docs.set_docs(docs)?; + Ok(self) } /// Set static documentation. /// /// This completely replaces any existing documentation. - pub fn static_docs(self, docs: &'static [&'static str]) -> Self { - self.docs.set_docs(docs); - self + pub fn static_docs(self, docs: &'static [&'static str]) -> Result { + self.docs.set_docs(docs)?; + Ok(self) } /// Mark the current type as a struct with named fields. @@ -639,12 +647,12 @@ where variants: &'static [&'static str], ) -> Result, ContextError> { let old = self.spec.replace(TypeSpecification::Enum(Enum { - variants: variants.iter().copied().map(Variant::new).collect(), + variants: variants.iter().copied().map(Variant::new).try_collect()?, })); if old.is_some() { return Err(ContextError::ConflictingTypeMeta { - item: self.item.to_owned(), + item: self.item.try_to_owned()?, type_info: T::type_info(), }); } @@ -683,7 +691,7 @@ where if old.is_some() { return Err(ContextError::ConflictingTypeMeta { - item: self.item.to_owned(), + item: self.item.try_to_owned()?, type_info: T::type_info(), }); } diff --git a/crates/rune/src/module/function_meta.rs b/crates/rune/src/module/function_meta.rs index 0e48f989b..053b2db08 100644 --- a/crates/rune/src/module/function_meta.rs +++ b/crates/rune/src/module/function_meta.rs @@ -1,9 +1,13 @@ use core::marker::PhantomData; -use crate::no_std::borrow::Cow; -use crate::no_std::prelude::*; use crate::no_std::sync::Arc; +use crate as rune; +use crate::alloc::borrow::Cow; +use crate::alloc::prelude::*; +#[cfg(feature = "doc")] +use crate::alloc::Vec; +use crate::alloc::{self, try_vec, Box}; use crate::compile::{self, meta, IntoComponent, ItemBuf, Named}; use crate::hash::Hash; use crate::macros::{MacroContext, TokenStream}; @@ -33,7 +37,7 @@ mod sealed { /// /// Calling and making use of `FunctionMeta` manually despite this warning might /// lead to future breakage. -pub type FunctionMeta = fn() -> FunctionMetaData; +pub type FunctionMeta = fn() -> alloc::Result; /// Type used to collect and store function metadata through the /// `#[rune::macro_]` macro. @@ -44,10 +48,9 @@ pub type FunctionMeta = fn() -> FunctionMetaData; /// /// Calling and making use of `MacroMeta` manually despite this warning might /// lead to future breakage. -pub type MacroMeta = fn() -> MacroMetaData; +pub type MacroMeta = fn() -> alloc::Result; /// Runtime data for a function. -#[derive(Clone)] pub struct FunctionData { pub(crate) item: ItemBuf, pub(crate) handler: Arc, @@ -65,7 +68,7 @@ pub struct FunctionData { impl FunctionData { #[inline] - pub(crate) fn new(name: N, f: F) -> Self + pub(crate) fn new(name: N, f: F) -> alloc::Result where F: Function, F::Return: MaybeTypeOf, @@ -74,8 +77,8 @@ impl FunctionData { A: FunctionArgs, K: FunctionKind, { - Self { - item: ItemBuf::with_item(name), + Ok(Self { + item: ItemBuf::with_item(name)?, handler: Arc::new(move |stack, args| f.fn_call(stack, args)), #[cfg(feature = "doc")] is_async: K::is_async(), @@ -86,13 +89,12 @@ impl FunctionData { #[cfg(feature = "doc")] return_type: F::Return::maybe_type_of(), #[cfg(feature = "doc")] - argument_types: A::into_box(), - } + argument_types: A::into_box()?, + }) } } /// Runtime data for a macro. -#[derive(Clone)] pub struct FunctionMacroData { pub(crate) item: ItemBuf, pub(crate) handler: Arc, @@ -100,7 +102,7 @@ pub struct FunctionMacroData { impl FunctionMacroData { #[inline] - pub(crate) fn new(name: N, f: F) -> Self + pub(crate) fn new(name: N, f: F) -> alloc::Result where F: 'static + Send @@ -109,15 +111,14 @@ impl FunctionMacroData { N: IntoIterator, N::Item: IntoComponent, { - Self { - item: ItemBuf::with_item(name), + Ok(Self { + item: ItemBuf::with_item(name)?, handler: Arc::new(f), - } + }) } } /// Runtime data for an attribute macro. -#[derive(Clone)] pub struct AttributeMacroData { pub(crate) item: ItemBuf, pub(crate) handler: Arc, @@ -125,7 +126,7 @@ pub struct AttributeMacroData { impl AttributeMacroData { #[inline] - pub(crate) fn new(name: N, f: F) -> Self + pub(crate) fn new(name: N, f: F) -> alloc::Result where F: 'static + Send @@ -138,15 +139,15 @@ impl AttributeMacroData { N: IntoIterator, N::Item: IntoComponent, { - Self { - item: ItemBuf::with_item(name), + Ok(Self { + item: ItemBuf::with_item(name)?, handler: Arc::new(f), - } + }) } } /// A descriptor for an instance function. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] #[non_exhaustive] #[doc(hidden)] pub struct AssociatedFunctionName { @@ -164,7 +165,7 @@ impl AssociatedFunctionName { associated: meta::AssociatedKind::IndexFn(protocol, index), function_parameters: Hash::EMPTY, #[cfg(feature = "doc")] - parameter_types: vec![], + parameter_types: Vec::new(), } } } @@ -173,41 +174,40 @@ impl AssociatedFunctionName { pub trait ToInstance: self::sealed::Sealed { /// Get information on the naming of the instance function. #[doc(hidden)] - fn to_instance(self) -> AssociatedFunctionName; + fn to_instance(self) -> alloc::Result; } /// Trait used to determine what can be used as an instance function name. pub trait ToFieldFunction: self::sealed::Sealed { #[doc(hidden)] - fn to_field_function(self, protocol: Protocol) -> AssociatedFunctionName; + fn to_field_function(self, protocol: Protocol) -> alloc::Result; } impl ToInstance for &'static str { #[inline] - fn to_instance(self) -> AssociatedFunctionName { - AssociatedFunctionName { + fn to_instance(self) -> alloc::Result { + Ok(AssociatedFunctionName { associated: meta::AssociatedKind::Instance(Cow::Borrowed(self)), function_parameters: Hash::EMPTY, #[cfg(feature = "doc")] - parameter_types: vec![], - } + parameter_types: Vec::new(), + }) } } impl ToFieldFunction for &'static str { #[inline] - fn to_field_function(self, protocol: Protocol) -> AssociatedFunctionName { - AssociatedFunctionName { + fn to_field_function(self, protocol: Protocol) -> alloc::Result { + Ok(AssociatedFunctionName { associated: meta::AssociatedKind::FieldFn(protocol, Cow::Borrowed(self)), function_parameters: Hash::EMPTY, #[cfg(feature = "doc")] - parameter_types: vec![], - } + parameter_types: Vec::new(), + }) } } /// Runtime data for an associated function. -#[derive(Clone)] pub struct AssociatedFunctionData { pub(crate) name: AssociatedFunctionName, pub(crate) handler: Arc, @@ -227,14 +227,14 @@ pub struct AssociatedFunctionData { impl AssociatedFunctionData { #[inline] - pub(crate) fn new(name: AssociatedFunctionName, f: F) -> Self + pub(crate) fn new(name: AssociatedFunctionName, f: F) -> alloc::Result where F: InstanceFunction, F::Return: MaybeTypeOf, A: FunctionArgs, K: FunctionKind, { - Self { + Ok(Self { name, handler: Arc::new(move |stack, args| f.fn_call(stack, args)), container: F::Instance::type_of(), @@ -248,17 +248,17 @@ impl AssociatedFunctionData { #[cfg(feature = "doc")] return_type: F::Return::maybe_type_of(), #[cfg(feature = "doc")] - argument_types: A::into_box(), - } + argument_types: A::into_box()?, + }) } /// Get associated key. - pub(crate) fn assoc_key(&self) -> AssociatedKey { - AssociatedKey { + pub(crate) fn assoc_key(&self) -> alloc::Result { + Ok(AssociatedKey { type_hash: self.container.hash, - kind: self.name.associated.clone(), + kind: self.name.associated.try_clone()?, parameters: self.name.function_parameters, - } + }) } } @@ -266,7 +266,6 @@ impl AssociatedFunctionData { /// /// Even though this is marked as `pub`, this is private API. If you use this it /// might cause breakage. -#[derive(Clone)] #[doc(hidden)] pub enum FunctionMetaKind { #[doc(hidden)] @@ -278,23 +277,23 @@ pub enum FunctionMetaKind { impl FunctionMetaKind { #[doc(hidden)] #[inline] - pub fn function(name: N, f: F) -> FunctionBuilder + pub fn function(name: N, f: F) -> alloc::Result> where F: Function, F::Return: MaybeTypeOf, A: FunctionArgs, K: FunctionKind, { - FunctionBuilder { + Ok(FunctionBuilder { name, f, _marker: PhantomData, - } + }) } #[doc(hidden)] #[inline] - pub fn instance(name: N, f: F) -> Self + pub fn instance(name: N, f: F) -> alloc::Result where N: ToInstance, F: InstanceFunction, @@ -302,7 +301,10 @@ impl FunctionMetaKind { A: FunctionArgs, K: FunctionKind, { - Self::AssociatedFunction(AssociatedFunctionData::new(name.to_instance(), f)) + Ok(Self::AssociatedFunction(AssociatedFunctionData::new( + name.to_instance()?, + f, + )?)) } } @@ -322,37 +324,41 @@ where { #[doc(hidden)] #[inline] - pub fn build(self) -> FunctionMetaKind + pub fn build(self) -> alloc::Result where N: IntoIterator, N::Item: IntoComponent, { - FunctionMetaKind::Function(FunctionData::new(self.name, self.f)) + Ok(FunctionMetaKind::Function(FunctionData::new( + self.name, self.f, + )?)) } #[doc(hidden)] #[inline] - pub fn build_associated(self) -> FunctionMetaKind + pub fn build_associated(self) -> alloc::Result where N: ToInstance, T: TypeOf + Named, { - FunctionMetaKind::AssociatedFunction(AssociatedFunctionData { - name: self.name.to_instance(), - handler: Arc::new(move |stack, args| self.f.fn_call(stack, args)), - container: T::type_of(), - container_type_info: T::type_info(), - #[cfg(feature = "doc")] - is_async: K::is_async(), - #[cfg(feature = "doc")] - deprecated: None, - #[cfg(feature = "doc")] - args: Some(F::args()), - #[cfg(feature = "doc")] - return_type: F::Return::maybe_type_of(), - #[cfg(feature = "doc")] - argument_types: A::into_box(), - }) + Ok(FunctionMetaKind::AssociatedFunction( + AssociatedFunctionData { + name: self.name.to_instance()?, + handler: Arc::new(move |stack, args| self.f.fn_call(stack, args)), + container: T::type_of(), + container_type_info: T::type_info(), + #[cfg(feature = "doc")] + is_async: K::is_async(), + #[cfg(feature = "doc")] + deprecated: None, + #[cfg(feature = "doc")] + args: Some(F::args()), + #[cfg(feature = "doc")] + return_type: F::Return::maybe_type_of(), + #[cfg(feature = "doc")] + argument_types: A::into_box()?, + }, + )) } } @@ -360,7 +366,6 @@ where /// /// Even though this is marked as `pub`, this is private API. If you use this it /// might cause breakage. -#[derive(Clone)] #[doc(hidden)] pub enum MacroMetaKind { #[doc(hidden)] @@ -372,7 +377,7 @@ pub enum MacroMetaKind { impl MacroMetaKind { #[doc(hidden)] #[inline] - pub fn function(name: N, f: F) -> Self + pub fn function(name: N, f: F) -> alloc::Result where F: 'static + Send @@ -381,12 +386,12 @@ impl MacroMetaKind { N: IntoIterator, N::Item: IntoComponent, { - Self::Function(FunctionMacroData::new(name, f)) + Ok(Self::Function(FunctionMacroData::new(name, f)?)) } #[doc(hidden)] #[inline] - pub fn attribute(name: N, f: F) -> Self + pub fn attribute(name: N, f: F) -> alloc::Result where F: 'static + Send @@ -399,7 +404,7 @@ impl MacroMetaKind { N: IntoIterator, N::Item: IntoComponent, { - Self::Attribute(AttributeMacroData::new(name, f)) + Ok(Self::Attribute(AttributeMacroData::new(name, f)?)) } } @@ -408,7 +413,6 @@ impl MacroMetaKind { /// Even though this is marked as `pub`, this is private API. If you use this it /// might cause breakage. #[doc(hidden)] -#[derive(Clone)] pub struct MacroMetaData { #[doc(hidden)] pub kind: MacroMetaKind, @@ -423,7 +427,6 @@ pub struct MacroMetaData { /// Even though this is marked as `pub`, this is private API. If you use this it /// might cause breakage. #[doc(hidden)] -#[derive(Clone)] pub struct FunctionMetaData { #[doc(hidden)] pub kind: FunctionMetaKind, @@ -439,7 +442,7 @@ pub struct FunctionMetaData { #[doc(hidden)] pub trait FunctionArgs { #[doc(hidden)] - fn into_box() -> Box<[Option]>; + fn into_box() -> alloc::Result]>>; } macro_rules! iter_function_args { @@ -450,8 +453,8 @@ macro_rules! iter_function_args { { #[inline] #[doc(hidden)] - fn into_box() -> Box<[Option]> { - vec![$(<$ty>::maybe_type_of(),)*].into() + fn into_box() -> alloc::Result]>> { + try_vec![$(<$ty>::maybe_type_of()),*].try_into_boxed_slice() } } } diff --git a/crates/rune/src/module/module.rs b/crates/rune/src/module/module.rs index eb9c1752d..ed8ca479b 100644 --- a/crates/rune/src/module/module.rs +++ b/crates/rune/src/module/module.rs @@ -1,9 +1,12 @@ use core::marker::PhantomData; -use crate::no_std::collections::{HashMap, HashSet}; -use crate::no_std::prelude::*; use crate::no_std::sync::Arc; +use crate as rune; +use crate::alloc::prelude::*; +#[cfg(feature = "doc")] +use crate::alloc::Box; +use crate::alloc::{self, HashMap, HashSet, String, Vec}; use crate::compile::{self, meta, ContextError, Docs, IntoComponent, ItemBuf, Named}; use crate::macros::{MacroContext, TokenStream}; use crate::module::function_meta::{ @@ -38,9 +41,9 @@ pub struct ModuleMetaData { /// /// Calling and making use of `ModuleMeta` manually despite this warning might /// lead to future breakage. -pub type ModuleMeta = fn() -> ModuleMetaData; +pub type ModuleMeta = fn() -> alloc::Result; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, TryClone, PartialEq, Eq, Hash)] enum Name { /// An associated key. Associated(AssociatedKey), @@ -100,34 +103,34 @@ impl Module { } /// Construct a new module for the given item. - pub fn with_item(iter: I) -> Self + pub fn with_item(iter: I) -> Result where I: IntoIterator, I::Item: IntoComponent, { - Self::inner_new(ItemBuf::with_item(iter)) + Ok(Self::inner_new(ItemBuf::with_item(iter)?)) } /// Construct a new module for the given crate. - pub fn with_crate(name: &str) -> Self { - Self::inner_new(ItemBuf::with_crate(name)) + pub fn with_crate(name: &str) -> Result { + Ok(Self::inner_new(ItemBuf::with_crate(name)?)) } /// Construct a new module for the given crate. - pub fn with_crate_item(name: &str, iter: I) -> Self + pub fn with_crate_item(name: &str, iter: I) -> Result where I: IntoIterator, I::Item: IntoComponent, { - Self::inner_new(ItemBuf::with_crate_item(name, iter)) + Ok(Self::inner_new(ItemBuf::with_crate_item(name, iter)?)) } /// Construct a new module from the given module meta. - pub fn from_meta(module_meta: ModuleMeta) -> Self { - let meta = module_meta(); + pub fn from_meta(module_meta: ModuleMeta) -> Result { + let meta = module_meta()?; let mut m = Self::inner_new(meta.item); - m.item_mut().static_docs(meta.docs); - m + m.item_mut().static_docs(meta.docs)?; + Ok(m) } fn inner_new(item: ItemBuf) -> Self { @@ -193,18 +196,18 @@ impl Module { /// /// let mut context = Context::new(); /// assert!(context.install(m).is_ok()); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn ty(&mut self) -> Result, ContextError> where T: ?Sized + Named + TypeOf + InstallWith, { - let item = ItemBuf::with_item([T::BASE_NAME]); + let item = ItemBuf::with_item([T::BASE_NAME])?; let hash = T::type_hash(); let type_parameters = T::type_parameters(); let type_info = T::type_info(); - if !self.names.insert(Name::Item(hash)) { + if !self.names.try_insert(Name::Item(hash))? { return Err(ContextError::ConflictingType { item, type_info, @@ -213,9 +216,9 @@ impl Module { } let index = self.types.len(); - self.types_hash.insert(hash, index); + self.types_hash.try_insert(hash, index)?; - self.types.push(ModuleType { + self.types.try_push(ModuleType { item, hash, type_parameters, @@ -223,7 +226,7 @@ impl Module { spec: None, constructor: None, docs: Docs::EMPTY, - }); + })?; T::install_with(self)?; @@ -246,8 +249,10 @@ impl Module { let type_hash = T::type_hash(); let Some(ty) = self.types_hash.get(&type_hash).map(|&i| &mut self.types[i]) else { + let full_name = String::try_from(T::full_name())?; + return Err(ContextError::MissingType { - item: ItemBuf::with_item(&[T::full_name()]), + item: ItemBuf::with_item(&[full_name])?, type_info: T::type_info(), }); }; @@ -298,15 +303,19 @@ impl Module { let type_hash = T::type_hash(); let Some(ty) = self.types_hash.get(&type_hash).map(|&i| &mut self.types[i]) else { + let full_name = String::try_from(T::full_name())?; + return Err(ContextError::MissingType { - item: ItemBuf::with_item(&[T::full_name()]), + item: ItemBuf::with_item(&[full_name])?, type_info: T::type_info(), }); }; let Some(TypeSpecification::Enum(en)) = &mut ty.spec else { + let full_name = String::try_from(T::full_name())?; + return Err(ContextError::MissingEnum { - item: ItemBuf::with_item(&[T::full_name()]), + item: ItemBuf::with_item(&[full_name])?, type_info: T::type_info(), }); }; @@ -356,9 +365,10 @@ impl Module { /// ``` /// use rune::Module; /// - /// let mut module = Module::with_crate_item("nonstd", ["ops"]); + /// let mut module = Module::with_crate_item("nonstd", ["ops"])?; /// module.generator_state(["GeneratorState"])?; - /// # Ok::<_, rune::Error>(()) + /// + /// Ok::<_, rune::support::Error>(()) pub fn generator_state( &mut self, name: N, @@ -371,7 +381,7 @@ impl Module { "GeneratorState", name, crate::runtime::static_type::GENERATOR_STATE_TYPE, - ); + )?; // Note: these numeric variants are magic, and must simply match up with // what's being used in the virtual machine implementation for these @@ -380,15 +390,15 @@ impl Module { "Complete", TypeCheck::GeneratorState(0), GeneratorState::Complete, - ); + )?; enum_.variant( "Yielded", TypeCheck::GeneratorState(1), GeneratorState::Yielded, - ); + )?; - self.internal_enums.push(enum_); + self.internal_enums.try_push(enum_)?; Ok(InternalEnumMut { enum_: self.internal_enums.last_mut().unwrap(), @@ -407,22 +417,24 @@ impl Module { /// ``` /// use rune::Module; /// - /// let mut module = Module::with_crate_item("nonstd", ["option"]); + /// let mut module = Module::with_crate_item("nonstd", ["option"])?; /// module.option(["Option"])?; - /// # Ok::<_, rune::Error>(()) + /// + /// Ok::<_, rune::support::Error>(()) pub fn option(&mut self, name: N) -> Result>, ContextError> where N: IntoIterator, N::Item: IntoComponent, { - let mut enum_ = InternalEnum::new("Option", name, crate::runtime::static_type::OPTION_TYPE); + let mut enum_ = + InternalEnum::new("Option", name, crate::runtime::static_type::OPTION_TYPE)?; // Note: these numeric variants are magic, and must simply match up with // what's being used in the virtual machine implementation for these // types. - enum_.variant("Some", TypeCheck::Option(0), Option::::Some); - enum_.variant("None", TypeCheck::Option(1), || Option::::None); - self.internal_enums.push(enum_); + enum_.variant("Some", TypeCheck::Option(0), Option::::Some)?; + enum_.variant("None", TypeCheck::Option(1), || Option::::None)?; + self.internal_enums.try_push(enum_)?; Ok(InternalEnumMut { enum_: self.internal_enums.last_mut().unwrap(), @@ -442,9 +454,10 @@ impl Module { /// ``` /// use rune::Module; /// - /// let mut module = Module::with_crate_item("nonstd", ["result"]); + /// let mut module = Module::with_crate_item("nonstd", ["result"])?; /// module.result(["Result"])?; - /// # Ok::<_, rune::Error>(()) + /// + /// Ok::<_, rune::support::Error>(()) pub fn result( &mut self, name: N, @@ -453,14 +466,15 @@ impl Module { N: IntoIterator, N::Item: IntoComponent, { - let mut enum_ = InternalEnum::new("Result", name, crate::runtime::static_type::RESULT_TYPE); + let mut enum_ = + InternalEnum::new("Result", name, crate::runtime::static_type::RESULT_TYPE)?; // Note: these numeric variants are magic, and must simply match up with // what's being used in the virtual machine implementation for these // types. - enum_.variant("Ok", TypeCheck::Result(0), Result::::Ok); - enum_.variant("Err", TypeCheck::Result(1), Result::::Err); - self.internal_enums.push(enum_); + enum_.variant("Ok", TypeCheck::Result(0), Result::::Ok)?; + enum_.variant("Err", TypeCheck::Result(1), Result::::Err)?; + self.internal_enums.try_push(enum_)?; Ok(InternalEnumMut { enum_: self.internal_enums.last_mut().unwrap(), @@ -479,7 +493,7 @@ impl Module { /// /// module.constant(["TEN"], 10)?.docs(["A global ten value."]); /// module.constant(["MyType", "TEN"], 10)?.docs(["Ten which looks like an associated constant."]); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn constant(&mut self, name: N, value: V) -> Result, ContextError> where @@ -487,7 +501,7 @@ impl Module { N::Item: IntoComponent, V: ToValue, { - let item = ItemBuf::with_item(name); + let item = ItemBuf::with_item(name)?; let hash = Hash::type_hash(&item); let value = match value.to_value() { @@ -500,15 +514,15 @@ impl Module { VmResult::Err(error) => return Err(ContextError::ValueError { error }), }; - if !self.names.insert(Name::Item(hash)) { + if !self.names.try_insert(Name::Item(hash))? { return Err(ContextError::ConflictingConstantName { item, hash }); } - self.constants.push(ModuleConstant { + self.constants.try_push(ModuleConstant { item, value, docs: Docs::EMPTY, - }); + })?; let c = self.constants.last_mut().unwrap(); Ok(ItemMut { docs: &mut c.docs }) @@ -531,6 +545,7 @@ impl Module { /// use rune::compile; /// use rune::macros::{quote, MacroContext, TokenStream}; /// use rune::parse::Parser; + /// use rune::alloc::prelude::*; /// /// /// Takes an identifier and converts it into a string. /// /// @@ -543,24 +558,25 @@ impl Module { /// fn ident_to_string(cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream) -> compile::Result { /// let mut p = Parser::from_token_stream(stream, cx.input_span()); /// let ident = p.parse_all::()?; - /// let ident = cx.resolve(ident)?.to_owned(); - /// let string = cx.lit(&ident); - /// Ok(quote!(#string).into_token_stream(cx)) + /// let ident = cx.resolve(ident)?.try_to_owned()?; + /// let string = cx.lit(&ident)?; + /// Ok(quote!(#string).into_token_stream(cx)?) /// } /// /// let mut m = Module::new(); /// m.macro_meta(ident_to_string)?; - /// Ok::<_, rune::Error>(()) + /// + /// Ok::<_, rune::support::Error>(()) /// ``` #[inline] pub fn macro_meta(&mut self, meta: MacroMeta) -> Result, ContextError> { - let meta = meta(); + let meta = meta()?; let docs = match meta.kind { MacroMetaKind::Function(data) => { let hash = Hash::type_hash(&data.item); - if !self.names.insert(Name::Macro(hash)) { + if !self.names.try_insert(Name::Macro(hash))? { return Err(ContextError::ConflictingMacroName { item: data.item, hash, @@ -568,19 +584,19 @@ impl Module { } let mut docs = Docs::EMPTY; - docs.set_docs(meta.docs); + docs.set_docs(meta.docs)?; - self.macros.push(ModuleMacro { + self.macros.try_push(ModuleMacro { item: data.item, handler: data.handler, docs, - }); + })?; &mut self.macros.last_mut().unwrap().docs } MacroMetaKind::Attribute(data) => { let hash = Hash::type_hash(&data.item); - if !self.names.insert(Name::AttributeMacro(hash)) { + if !self.names.try_insert(Name::AttributeMacro(hash))? { return Err(ContextError::ConflictingMacroName { item: data.item, hash, @@ -588,13 +604,13 @@ impl Module { } let mut docs = Docs::EMPTY; - docs.set_docs(meta.docs); + docs.set_docs(meta.docs)?; - self.attribute_macros.push(ModuleAttributeMacro { + self.attribute_macros.try_push(ModuleAttributeMacro { item: data.item, handler: data.handler, docs, - }); + })?; &mut self.attribute_macros.last_mut().unwrap().docs } }; @@ -615,18 +631,20 @@ impl Module { /// use rune::compile; /// use rune::macros::{quote, MacroContext, TokenStream}; /// use rune::parse::Parser; + /// use rune::alloc::prelude::*; /// /// fn ident_to_string(cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream) -> compile::Result { /// let mut p = Parser::from_token_stream(stream, cx.input_span()); /// let ident = p.parse_all::()?; - /// let ident = cx.resolve(ident)?.to_owned(); - /// let string = cx.lit(&ident); - /// Ok(quote!(#string).into_token_stream(cx)) + /// let ident = cx.resolve(ident)?.try_to_owned()?; + /// let string = cx.lit(&ident)?; + /// Ok(quote!(#string).into_token_stream(cx)?) /// } /// /// let mut m = Module::new(); /// m.macro_(["ident_to_string"], ident_to_string)?; - /// # Ok::<_, rune::Error>(()) + /// + /// Ok::<_, rune::support::Error>(()) /// ``` pub fn macro_(&mut self, name: N, f: M) -> Result, ContextError> where @@ -637,20 +655,20 @@ impl Module { N: IntoIterator, N::Item: IntoComponent, { - let item = ItemBuf::with_item(name); + let item = ItemBuf::with_item(name)?; let hash = Hash::type_hash(&item); - if !self.names.insert(Name::Macro(hash)) { + if !self.names.try_insert(Name::Macro(hash))? { return Err(ContextError::ConflictingMacroName { item, hash }); } let handler: Arc = Arc::new(f); - self.macros.push(ModuleMacro { + self.macros.try_push(ModuleMacro { item, handler, docs: Docs::EMPTY, - }); + })?; let m = self.macros.last_mut().unwrap(); @@ -677,12 +695,13 @@ impl Module { /// /// let mut input = Parser::from_token_stream(input, cx.input_span()); /// fun.name = input.parse_all::>()?.value; - /// Ok(quote!(#fun).into_token_stream(cx)) + /// Ok(quote!(#fun).into_token_stream(cx)?) /// } /// /// let mut m = Module::new(); /// m.attribute_macro(["rename_fn"], rename_fn)?; - /// # Ok::<_, rune::Error>(()) + /// + /// Ok::<_, rune::support::Error>(()) /// ``` pub fn attribute_macro(&mut self, name: N, f: M) -> Result, ContextError> where @@ -697,20 +716,20 @@ impl Module { N: IntoIterator, N::Item: IntoComponent, { - let item = ItemBuf::with_item(name); + let item = ItemBuf::with_item(name)?; let hash = Hash::type_hash(&item); - if !self.names.insert(Name::AttributeMacro(hash)) { + if !self.names.try_insert(Name::AttributeMacro(hash))? { return Err(ContextError::ConflictingMacroName { item, hash }); } let handler: Arc = Arc::new(f); - self.attribute_macros.push(ModuleAttributeMacro { + self.attribute_macros.try_push(ModuleAttributeMacro { item, handler, docs: Docs::EMPTY, - }); + })?; let m = self.attribute_macros.last_mut().unwrap(); @@ -740,7 +759,7 @@ impl Module { /// /// /// This is a pretty neat download function /// #[rune::function] - /// async fn download(url: Ref) -> rune::Result { + /// async fn download(url: Ref) -> rune::support::Result { /// todo!() /// } /// @@ -776,7 +795,7 @@ impl Module { /// } /// /// #[rune::function(instance, path = Self::download)] - /// async fn download(this: Ref, url: Ref) -> rune::Result<()> { + /// async fn download(this: Ref, url: Ref) -> rune::support::Result<()> { /// todo!() /// } /// } @@ -786,23 +805,23 @@ impl Module { /// m.ty::()?; /// m.function_meta(MyBytes::len)?; /// m.function_meta(MyBytes::download)?; - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] pub fn function_meta(&mut self, meta: FunctionMeta) -> Result, ContextError> { - let meta = meta(); + let meta = meta()?; match meta.kind { FunctionMetaKind::Function(data) => { let mut docs = Docs::EMPTY; - docs.set_docs(meta.docs); - docs.set_arguments(meta.arguments); + docs.set_docs(meta.docs)?; + docs.set_arguments(meta.arguments)?; self.function_inner(data, docs) } FunctionMetaKind::AssociatedFunction(data) => { let mut docs = Docs::EMPTY; - docs.set_docs(meta.docs); - docs.set_arguments(meta.arguments); + docs.set_docs(meta.docs)?; + docs.set_arguments(meta.arguments)?; self.assoc_fn(data, docs) } } @@ -825,7 +844,7 @@ impl Module { /// let mut module = Module::default(); /// /// module.function(["add_ten"], add_ten)?.docs(["Adds 10 to any integer passed in."]); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` /// /// Asynchronous function: @@ -847,7 +866,7 @@ impl Module { /// /// module.function(["download_quote"], download_quote)? /// .docs(["Download a random quote from the internet."]); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn function(&mut self, name: N, f: F) -> Result, ContextError> where @@ -858,7 +877,7 @@ impl Module { A: FunctionArgs, K: FunctionKind, { - self.function_inner(FunctionData::new(name, f), Docs::EMPTY) + self.function_inner(FunctionData::new(name, f)?, Docs::EMPTY) } /// See [`Module::function`]. @@ -871,7 +890,7 @@ impl Module { N::Item: IntoComponent, A: FunctionArgs, { - self.function_inner(FunctionData::new(name, f), Docs::EMPTY) + self.function_inner(FunctionData::new(name, f)?, Docs::EMPTY) } /// Register an instance function. @@ -1015,7 +1034,7 @@ impl Module { /// m.ty::()?; /// m.function_meta(MyBytes::new)?; /// m.function_meta(MyBytes::len)?; - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` /// /// Asynchronous function: @@ -1050,7 +1069,7 @@ impl Module { /// /// module.ty::()?; /// module.function_meta(Client::download)?; - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn associated_function( &mut self, @@ -1065,7 +1084,7 @@ impl Module { K: FunctionKind, { self.assoc_fn( - AssociatedFunctionData::new(name.to_instance(), f), + AssociatedFunctionData::new(name.to_instance()?, f)?, Docs::EMPTY, ) } @@ -1113,7 +1132,7 @@ impl Module { A: FunctionArgs, { self.assoc_fn( - AssociatedFunctionData::new(name.to_field_function(protocol), f), + AssociatedFunctionData::new(name.to_field_function(protocol)?, f)?, Docs::EMPTY, ) } @@ -1152,7 +1171,7 @@ impl Module { A: FunctionArgs, { let name = AssociatedFunctionName::index(protocol, index); - self.assoc_fn(AssociatedFunctionData::new(name, f), Docs::EMPTY) + self.assoc_fn(AssociatedFunctionData::new(name, f)?, Docs::EMPTY) } /// See [`Module::index_function`]. @@ -1202,7 +1221,7 @@ impl Module { /// sum.docs([ /// "Sum all numbers provided to the function." /// ]); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn raw_fn(&mut self, name: N, f: F) -> Result, ContextError> where @@ -1210,14 +1229,14 @@ impl Module { N: IntoIterator, N::Item: IntoComponent, { - let item = ItemBuf::with_item(name); + let item = ItemBuf::with_item(name)?; let hash = Hash::type_hash(&item); - if !self.names.insert(Name::Item(hash)) { + if !self.names.try_insert(Name::Item(hash))? { return Err(ContextError::ConflictingFunctionName { item, hash }); } - self.functions.push(ModuleFunction { + self.functions.try_push(ModuleFunction { item, handler: Arc::new(move |stack, args| f(stack, args)), #[cfg(feature = "doc")] @@ -1229,9 +1248,9 @@ impl Module { #[cfg(feature = "doc")] return_type: None, #[cfg(feature = "doc")] - argument_types: Box::from([]), + argument_types: Box::default(), docs: Docs::EMPTY, - }); + })?; let last = self.functions.last_mut().unwrap(); @@ -1257,14 +1276,14 @@ impl Module { ) -> Result, ContextError> { let hash = Hash::type_hash(&data.item); - if !self.names.insert(Name::Item(hash)) { + if !self.names.try_insert(Name::Item(hash))? { return Err(ContextError::ConflictingFunctionName { item: data.item, hash, }); } - self.functions.push(ModuleFunction { + self.functions.try_push(ModuleFunction { item: data.item, handler: data.handler, #[cfg(feature = "doc")] @@ -1278,7 +1297,7 @@ impl Module { #[cfg(feature = "doc")] argument_types: data.argument_types, docs, - }); + })?; let last = self.functions.last_mut().unwrap(); @@ -1303,36 +1322,36 @@ impl Module { data: AssociatedFunctionData, docs: Docs, ) -> Result, ContextError> { - if !self.names.insert(Name::Associated(data.assoc_key())) { + if !self.names.try_insert(Name::Associated(data.assoc_key()?))? { return Err(match data.name.associated { meta::AssociatedKind::Protocol(protocol) => { ContextError::ConflictingProtocolFunction { type_info: data.container_type_info, - name: protocol.name.into(), + name: protocol.name.try_into()?, } } meta::AssociatedKind::FieldFn(protocol, field) => { ContextError::ConflictingFieldFunction { type_info: data.container_type_info, - name: protocol.name.into(), - field: field.into(), + name: protocol.name.try_into()?, + field: field.try_into()?, } } meta::AssociatedKind::IndexFn(protocol, index) => { ContextError::ConflictingIndexFunction { type_info: data.container_type_info, - name: protocol.name.into(), + name: protocol.name.try_into()?, index, } } meta::AssociatedKind::Instance(name) => ContextError::ConflictingInstanceFunction { type_info: data.container_type_info, - name: name.into(), + name: name.try_into()?, }, }); } - self.associated.push(ModuleAssociated { + self.associated.try_push(ModuleAssociated { container: data.container, container_type_info: data.container_type_info, name: data.name, @@ -1348,7 +1367,7 @@ impl Module { #[cfg(feature = "doc")] argument_types: data.argument_types, docs, - }); + })?; let last = self.associated.last_mut().unwrap(); diff --git a/crates/rune/src/modules/any.rs b/crates/rune/src/modules/any.rs index 6afd5385b..f913624a8 100644 --- a/crates/rune/src/modules/any.rs +++ b/crates/rune/src/modules/any.rs @@ -14,10 +14,10 @@ use crate::{ContextError, Module}; /// constructed through the [`Type::of_val`] function. #[rune::module(::std::any)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta); + let mut m = Module::from_meta(self::module_meta)?; m.ty::()? - .docs(["Represents a type in the Rune type system."]); + .docs(["Represents a type in the Rune type system."])?; m.function_meta(type_of_val)?; m.function_meta(type_name_of_val)?; m.function_meta(format_type)?; diff --git a/crates/rune/src/modules/bytes.rs b/crates/rune/src/modules/bytes.rs index 2331fd4b1..b608b1fbc 100644 --- a/crates/rune/src/modules/bytes.rs +++ b/crates/rune/src/modules/bytes.rs @@ -1,14 +1,14 @@ //! The `std::bytes` module. -use crate::no_std::prelude::*; - use crate as rune; -use crate::runtime::Bytes; +use crate::alloc::prelude::*; +use crate::alloc::Vec; +use crate::runtime::{Bytes, VmResult}; use crate::{ContextError, Module}; /// Construct the `std::bytes` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["bytes"]); + let mut module = Module::with_crate_item("std", ["bytes"])?; module.ty::()?; module.function_meta(new)?; @@ -57,8 +57,8 @@ pub const fn new() -> Bytes { /// ``` #[rune::function(free, path = Bytes::with_capacity)] #[inline] -pub fn with_capacity(capacity: usize) -> Bytes { - Bytes::with_capacity(capacity) +pub fn with_capacity(capacity: usize) -> VmResult { + VmResult::Ok(vm_try!(Bytes::with_capacity(capacity))) } /// Convert a byte array into bytes. @@ -103,8 +103,8 @@ pub fn into_vec(bytes: Bytes) -> Vec { /// ``` #[rune::function(instance)] #[inline] -pub fn as_vec(bytes: &Bytes) -> Vec { - bytes.as_slice().to_vec() +pub fn as_vec(bytes: &Bytes) -> VmResult> { + VmResult::Ok(vm_try!(Vec::try_from(bytes.as_slice()))) } /// Extend these bytes with another collection of bytes. @@ -118,8 +118,9 @@ pub fn as_vec(bytes: &Bytes) -> Vec { /// ``` #[rune::function(instance)] #[inline] -pub fn extend(this: &mut Bytes, other: &Bytes) { - this.extend(other); +pub fn extend(this: &mut Bytes, other: &Bytes) -> VmResult<()> { + vm_try!(this.extend(other)); + VmResult::Ok(()) } /// Extend this bytes collection with a string. @@ -132,8 +133,9 @@ pub fn extend(this: &mut Bytes, other: &Bytes) { /// assert_eq!(bytes, b"abcdefgh"); /// ``` #[rune::function(instance)] -pub fn extend_str(this: &mut Bytes, s: &str) { - this.extend(s.as_bytes()); +pub fn extend_str(this: &mut Bytes, s: &str) -> VmResult<()> { + vm_try!(this.extend(s.as_bytes())); + VmResult::Ok(()) } /// Pop the last byte. @@ -258,8 +260,9 @@ fn clear(this: &mut Bytes) { /// assert!(vec.capacity() >= 11); /// ``` #[rune::function(instance)] -fn reserve(this: &mut Bytes, additional: usize) { - this.reserve(additional); +fn reserve(this: &mut Bytes, additional: usize) -> VmResult<()> { + vm_try!(this.reserve(additional)); + VmResult::Ok(()) } /// Reserves the minimum capacity for at least `additional` more elements to be @@ -287,8 +290,9 @@ fn reserve(this: &mut Bytes, additional: usize) { /// assert!(vec.capacity() >= 11); /// ``` #[rune::function(instance)] -fn reserve_exact(this: &mut Bytes, additional: usize) { - this.reserve_exact(additional) +fn reserve_exact(this: &mut Bytes, additional: usize) -> VmResult<()> { + vm_try!(this.reserve_exact(additional)); + VmResult::Ok(()) } /// Clone the byte array. @@ -305,8 +309,8 @@ fn reserve_exact(this: &mut Bytes, additional: usize) { /// assert_eq!(b, b"hello world"); /// ``` #[rune::function(instance)] -fn clone(this: &Bytes) -> Bytes { - this.clone() +fn clone(this: &Bytes) -> VmResult { + VmResult::Ok(vm_try!(this.try_clone())) } /// Shrinks the capacity of the byte array as much as possible. @@ -324,6 +328,7 @@ fn clone(this: &Bytes) -> Bytes { /// assert!(bytes.capacity() >= 3); /// ``` #[rune::function(instance)] -fn shrink_to_fit(this: &mut Bytes) { - this.shrink_to_fit(); +fn shrink_to_fit(this: &mut Bytes) -> VmResult<()> { + vm_try!(this.shrink_to_fit()); + VmResult::Ok(()) } diff --git a/crates/rune/src/modules/capture_io.rs b/crates/rune/src/modules/capture_io.rs index 7d52174b0..251e9988b 100644 --- a/crates/rune/src/modules/capture_io.rs +++ b/crates/rune/src/modules/capture_io.rs @@ -25,7 +25,7 @@ use crate::{ContextError, Module, Value}; /// Provide a bunch of `std` functions that can be used during tests to capture output. pub fn module(io: &CaptureIo) -> Result { - let mut module = Module::with_crate_item("std", ["io"]); + let mut module = Module::with_crate_item("std", ["io"])?; let o = io.clone(); diff --git a/crates/rune/src/modules/char.rs b/crates/rune/src/modules/char.rs index 1aff0f457..123723b47 100644 --- a/crates/rune/src/modules/char.rs +++ b/crates/rune/src/modules/char.rs @@ -9,7 +9,7 @@ use crate as rune; /// Construct the `std::char` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["char"]); + let mut module = Module::with_crate_item("std", ["char"])?; module.ty::()?; module.function_meta(from_i64)?; diff --git a/crates/rune/src/modules/cmp.rs b/crates/rune/src/modules/cmp.rs index 7f93f0880..781c694b2 100644 --- a/crates/rune/src/modules/cmp.rs +++ b/crates/rune/src/modules/cmp.rs @@ -9,7 +9,7 @@ use crate::{ContextError, Module}; /// Construct the `std::cmp` module. pub fn module() -> Result { - let mut m = Module::with_crate_item("std", ["cmp"]); + let mut m = Module::with_crate_item("std", ["cmp"])?; { let ty = m.ty::()?.docs([ @@ -30,24 +30,24 @@ pub fn module() -> Result { "let result = cmp(2, 1);", "assert_eq!(Ordering::Greater, result);", "```", - ]); + ])?; let mut ty = ty.make_enum(&["Less", "Equal", "Greater"])?; ty.variant_mut(0)? .make_empty()? .constructor(|| Ordering::Less)? - .docs(["An ordering where a compared value is less than another."]); + .docs(["An ordering where a compared value is less than another."])?; ty.variant_mut(1)? .make_empty()? .constructor(|| Ordering::Equal)? - .docs(["An ordering where a compared value is equal to another."]); + .docs(["An ordering where a compared value is equal to another."])?; ty.variant_mut(2)? .make_empty()? .constructor(|| Ordering::Greater)? - .docs(["An ordering where a compared value is greater than another."]); + .docs(["An ordering where a compared value is greater than another."])?; } m.function_meta(ordering_partial_eq)?; diff --git a/crates/rune/src/modules/collections.rs b/crates/rune/src/modules/collections.rs index 62eed02b6..d69b2a76d 100644 --- a/crates/rune/src/modules/collections.rs +++ b/crates/rune/src/modules/collections.rs @@ -18,7 +18,7 @@ use crate as rune; #[rune::module(::std::collections)] /// The `std::collections` module. pub fn module() -> Result { - let mut module = Module::from_meta(self::module_meta); + let mut module = Module::from_meta(self::module_meta)?; #[cfg(feature = "alloc")] hash_map::setup(&mut module)?; #[cfg(feature = "alloc")] diff --git a/crates/rune/src/modules/collections/hash_map.rs b/crates/rune/src/modules/collections/hash_map.rs index 0f800d805..fb7ba64b0 100644 --- a/crates/rune/src/modules/collections/hash_map.rs +++ b/crates/rune/src/modules/collections/hash_map.rs @@ -1,6 +1,6 @@ use crate as rune; use crate::alloc::fmt::TryWrite; -use crate::alloc::{Global, TryClone}; +use crate::alloc::prelude::*; use crate::hashbrown::Table; use crate::runtime::{ EnvProtocolCaller, Formatter, FromValue, Iterator, ProtocolCaller, Ref, Value, VmErrorKind, @@ -56,7 +56,7 @@ impl HashMap { #[rune::function(keep, path = Self::new)] fn new() -> Self { Self { - table: Table::new_in(Global), + table: Table::new(), } } @@ -75,7 +75,7 @@ impl HashMap { #[rune::function(keep, path = Self::with_capacity)] fn with_capacity(capacity: usize) -> VmResult { VmResult::Ok(Self { - table: vm_try!(Table::try_with_capacity_in(capacity, Global)), + table: vm_try!(Table::try_with_capacity(capacity)), }) } diff --git a/crates/rune/src/modules/collections/hash_set.rs b/crates/rune/src/modules/collections/hash_set.rs index eefcc871a..3b2cc61d9 100644 --- a/crates/rune/src/modules/collections/hash_set.rs +++ b/crates/rune/src/modules/collections/hash_set.rs @@ -5,7 +5,7 @@ use core::ptr; use crate as rune; use crate::alloc::hashbrown::raw::RawIter; -use crate::alloc::{Global, TryClone}; +use crate::alloc::prelude::*; use crate::hashbrown::{IterRef, Table}; use crate::runtime::{ EnvProtocolCaller, Formatter, Iterator, ProtocolCaller, RawRef, Ref, Value, VmResult, @@ -59,7 +59,7 @@ impl HashSet { #[rune::function(keep, path = Self::new)] fn new() -> Self { Self { - table: Table::new_in(Global), + table: Table::new(), } } @@ -80,7 +80,7 @@ impl HashSet { #[rune::function(keep, path = Self::with_capacity)] fn with_capacity(capacity: usize) -> VmResult { VmResult::Ok(Self { - table: vm_try!(Table::try_with_capacity_in(capacity, Global)), + table: vm_try!(Table::try_with_capacity(capacity)), }) } @@ -303,8 +303,8 @@ impl HashSet { // use longest as lead and then append any missing that are in second let iter = if this.as_ref().len() >= other.as_ref().len() { - let this_iter = Table::<_, Global>::iter_ref_raw(this); - let other_iter = Table::<_, Global>::iter_ref_raw(other); + let this_iter = Table::iter_ref_raw(this); + let other_iter = Table::iter_ref_raw(other); Union { this, @@ -313,8 +313,8 @@ impl HashSet { _guards: (this_guard, other_guard), } } else { - let this_iter = Table::<_, Global>::iter_ref_raw(other); - let other_iter = Table::<_, Global>::iter_ref_raw(this); + let this_iter = Table::iter_ref_raw(other); + let other_iter = Table::iter_ref_raw(this); Union { this: other, @@ -424,7 +424,7 @@ impl HashSet { where P: ?Sized + ProtocolCaller, { - let mut set = vm_try!(Table::try_with_capacity_in(it.size_hint().0, Global)); + let mut set = vm_try!(Table::try_with_capacity(it.size_hint().0)); while let Some(key) = vm_try!(it.next()) { vm_try!(set.insert_with(key, (), caller)); diff --git a/crates/rune/src/modules/collections/vec_deque.rs b/crates/rune/src/modules/collections/vec_deque.rs index 2e8f93ae0..9ac25aafd 100644 --- a/crates/rune/src/modules/collections/vec_deque.rs +++ b/crates/rune/src/modules/collections/vec_deque.rs @@ -2,8 +2,9 @@ use core::cmp::Ordering; use core::iter; use crate as rune; +use crate::alloc; use crate::alloc::fmt::TryWrite; -use crate::alloc::{self, Error, Global, TryClone}; +use crate::alloc::prelude::*; use crate::runtime::{ EnvProtocolCaller, Formatter, Iterator, Protocol, ProtocolCaller, RawRef, Ref, Value, VmErrorKind, VmResult, @@ -31,7 +32,7 @@ pub(super) fn setup(m: &mut Module) -> Result<(), ContextError> { "[`pop_front`]: VecDeque::pop_front", "[`extend`]: VecDeque::extend", "[`append`]: VecDeque::append", - ]); + ])?; m.function_meta(VecDeque::new)?; m.function_meta(VecDeque::with_capacity)?; @@ -100,7 +101,7 @@ impl VecDeque { #[rune::function(path = Self::with_capacity)] fn with_capacity(count: usize) -> VmResult { VmResult::Ok(Self { - inner: vm_try!(alloc::VecDeque::try_with_capacity_in(count, Global)), + inner: vm_try!(alloc::VecDeque::try_with_capacity(count)), }) } @@ -503,10 +504,7 @@ impl VecDeque { } pub(crate) fn from_iter(mut it: Iterator) -> VmResult { - let mut inner = vm_try!(alloc::VecDeque::try_with_capacity_in( - it.size_hint().0, - Global - )); + let mut inner = vm_try!(alloc::VecDeque::try_with_capacity(it.size_hint().0,)); while let Some(value) = vm_try!(it.next()) { vm_try!(inner.try_push_back(value)); @@ -742,14 +740,14 @@ impl VecDeque { impl TryClone for VecDeque { #[inline] - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { inner: self.inner.try_clone()?, }) } #[inline] - fn try_clone_from(&mut self, source: &Self) -> Result<(), Error> { + fn try_clone_from(&mut self, source: &Self) -> alloc::Result<()> { self.inner.try_clone_from(&source.inner) } } diff --git a/crates/rune/src/modules/core.rs b/crates/rune/src/modules/core.rs index 907b765cf..a3c29c117 100644 --- a/crates/rune/src/modules/core.rs +++ b/crates/rune/src/modules/core.rs @@ -3,6 +3,7 @@ use crate::no_std::prelude::*; use crate as rune; +use crate::alloc::prelude::*; use crate::compile; use crate::macros::{quote, FormatArgs, MacroContext, TokenStream}; use crate::parse::Parser; @@ -12,13 +13,15 @@ use crate::{ContextError, Module}; #[rune::module(::std)] /// The Rune standard library. pub fn module() -> Result { - let mut module = Module::from_meta(self::module_meta).with_unique("std"); + let mut module = Module::from_meta(self::module_meta)?.with_unique("std"); - module.ty::()?.docs(["The primitive boolean type."]); - module.ty::()?.docs(["The primitive character type."]); - module.ty::()?.docs(["The primitive byte type."]); - module.ty::()?.docs(["The primitive float type."]); - module.ty::()?.docs(["The primitive integer type."]); + module.ty::()?.docs(["The primitive boolean type."])?; + module + .ty::()? + .docs(["The primitive character type."])?; + module.ty::()?.docs(["The primitive byte type."])?; + module.ty::()?.docs(["The primitive float type."])?; + module.ty::()?.docs(["The primitive integer type."])?; module.function_meta(panic)?; module.function_meta(is_readable)?; @@ -161,9 +164,9 @@ pub(crate) fn stringify_macro( cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream, ) -> compile::Result { - let lit = cx.stringify(stream).to_string(); - let lit = cx.lit(lit); - Ok(quote!(#lit).into_token_stream(cx)) + let lit = cx.stringify(stream)?.try_to_string()?; + let lit = cx.lit(lit)?; + Ok(quote!(#lit).into_token_stream(cx)?) } /// Cause a vm panic with a formatted message. @@ -179,5 +182,5 @@ pub(crate) fn panic_macro( let mut p = Parser::from_token_stream(stream, cx.input_span()); let args = p.parse_all::()?; let expanded = args.expand(cx)?; - Ok(quote!(::std::panic(#expanded)).into_token_stream(cx)) + Ok(quote!(::std::panic(#expanded)).into_token_stream(cx)?) } diff --git a/crates/rune/src/modules/disable_io.rs b/crates/rune/src/modules/disable_io.rs index 46a7b1c0f..5c4528f93 100644 --- a/crates/rune/src/modules/disable_io.rs +++ b/crates/rune/src/modules/disable_io.rs @@ -14,7 +14,7 @@ use crate::{ContextError, Module}; /// Provide a bunch of `std::io` functions which will cause any output to be ignored. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["io"]); + let mut module = Module::with_crate_item("std", ["io"])?; module.function(["print"], move |_: &str| {})?; diff --git a/crates/rune/src/modules/f64.rs b/crates/rune/src/modules/f64.rs index f2de1981f..01ab77e04 100644 --- a/crates/rune/src/modules/f64.rs +++ b/crates/rune/src/modules/f64.rs @@ -9,10 +9,10 @@ use crate::{ContextError, Module}; /// Install the core package into the given functions namespace. pub fn module() -> Result { - let mut m = Module::with_crate_item("std", ["f64"]); + let mut m = Module::with_crate_item("std", ["f64"])?; m.function_meta(parse)? - .deprecated("Use std::string::parse:: instead"); + .deprecated("Use std::string::parse:: instead")?; m.function_meta(is_nan)?; m.function_meta(is_infinite)?; m.function_meta(is_finite)?; diff --git a/crates/rune/src/modules/fmt.rs b/crates/rune/src/modules/fmt.rs index 5553dc42b..9c31d1a02 100644 --- a/crates/rune/src/modules/fmt.rs +++ b/crates/rune/src/modules/fmt.rs @@ -12,7 +12,7 @@ use crate::{ContextError, Module}; /// Construct the `std::fmt` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["fmt"]).with_unique("std::fmt"); + let mut module = Module::with_crate_item("std", ["fmt"])?.with_unique("std::fmt"); module.ty::()?; module.ty::()?; module.ty::()?; @@ -45,5 +45,5 @@ pub(crate) fn format( let args = p.parse::()?; p.eof()?; let expanded = args.expand(cx)?; - Ok(expanded.into_token_stream(cx)) + Ok(expanded.into_token_stream(cx)?) } diff --git a/crates/rune/src/modules/future.rs b/crates/rune/src/modules/future.rs index 3d2154af6..65f1bdfdf 100644 --- a/crates/rune/src/modules/future.rs +++ b/crates/rune/src/modules/future.rs @@ -6,14 +6,14 @@ use crate::{ContextError, Module}; /// Construct the `std::future` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["future"]); + let mut module = Module::with_crate_item("std", ["future"])?; module.ty::()?; module .raw_fn(["join"], raw_join)? .is_async(true) .args(1) - .argument_types([None]) + .argument_types([None])? .docs([ "Waits for a collection of futures to complete and joins their result.", "", @@ -43,7 +43,7 @@ pub fn module() -> Result { "let () = std::future::join(()).await;", "let [] = std::future::join([]).await;", "```", - ]); + ])?; Ok(module) } diff --git a/crates/rune/src/modules/generator.rs b/crates/rune/src/modules/generator.rs index c49f3700b..950acfe90 100644 --- a/crates/rune/src/modules/generator.rs +++ b/crates/rune/src/modules/generator.rs @@ -5,5 +5,5 @@ use crate::{ContextError, Module}; /// Construct the `std::generator` module. #[deprecated = "Generators have been moved into std::ops"] pub fn module() -> Result { - Ok(Module::with_crate_item("std", ["generator"])) + Module::with_crate_item("std", ["generator"]) } diff --git a/crates/rune/src/modules/hash.rs b/crates/rune/src/modules/hash.rs index 127ad55e6..46d3ced9b 100644 --- a/crates/rune/src/modules/hash.rs +++ b/crates/rune/src/modules/hash.rs @@ -9,7 +9,7 @@ use crate::{ContextError, Module}; /// Types for dealing with hashing in Rune. pub fn module() -> Result { #[allow(unused_mut)] - let mut module = Module::from_meta(self::module_meta); + let mut module = Module::from_meta(self::module_meta)?; #[cfg(feature = "std")] module.ty::()?; Ok(module) diff --git a/crates/rune/src/modules/i64.rs b/crates/rune/src/modules/i64.rs index 479a49052..da538e30b 100644 --- a/crates/rune/src/modules/i64.rs +++ b/crates/rune/src/modules/i64.rs @@ -11,7 +11,7 @@ use crate::{ContextError, Module}; /// Construct the `std::i64` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["i64"]); + let mut module = Module::with_crate_item("std", ["i64"])?; module.function(["parse"], parse)?; module.function_meta(to_float)?; @@ -60,7 +60,7 @@ pub fn module() -> Result { "```rune", "assert_eq!(i64::MIN, -9223372036854775808);", "```", - ]); + ])?; module.constant(["MAX"], i64::MAX)?.docs([ "The largest value that can be represented by this integer type", @@ -73,7 +73,7 @@ pub fn module() -> Result { "```rune", "assert_eq!(i64::MAX, 9223372036854775807);", "```", - ]); + ])?; Ok(module) } diff --git a/crates/rune/src/modules/io.rs b/crates/rune/src/modules/io.rs index f54c2a694..9e5e7996a 100644 --- a/crates/rune/src/modules/io.rs +++ b/crates/rune/src/modules/io.rs @@ -12,7 +12,7 @@ use crate::{ContextError, Module}; /// Construct the `std::io` module. pub fn module(stdio: bool) -> Result { - let mut module = Module::with_crate_item("std", ["io"]).with_unique("std::io"); + let mut module = Module::with_crate_item("std", ["io"])?.with_unique("std::io"); module.item_mut().docs([ "The std::io module contains a number of common things", @@ -28,7 +28,7 @@ pub fn module(stdio: bool) -> Result { "Their definitions can be omitted from the built-in standard library, and", "can then easily be defined by third party modules allowing for printing", "to be hooked up to whatever system you want.", - ]); + ])?; module.ty::()?; module.function_meta(io_error_string_display)?; @@ -55,7 +55,7 @@ pub fn module(stdio: bool) -> Result { "", "dbg(number, string);", "```", - ]); + ])?; } // These are unconditionally included, but using them might cause a @@ -107,7 +107,7 @@ pub(crate) fn dbg_macro( cx: &mut MacroContext<'_, '_, '_>, stream: &TokenStream, ) -> compile::Result { - Ok(quote!(::std::io::dbg(#stream)).into_token_stream(cx)) + Ok(quote!(::std::io::dbg(#stream)).into_token_stream(cx)?) } /// Prints to output. @@ -129,7 +129,7 @@ pub(crate) fn print_macro( let mut p = Parser::from_token_stream(stream, cx.input_span()); let args = p.parse_all::()?; let expanded = args.expand(cx)?; - Ok(quote!(::std::io::print(#expanded)).into_token_stream(cx)) + Ok(quote!(::std::io::print(#expanded)).into_token_stream(cx)?) } /// Prints to output. @@ -176,7 +176,7 @@ pub(crate) fn println_macro( let mut p = Parser::from_token_stream(stream, cx.input_span()); let args = p.parse_all::()?; let expanded = args.expand(cx)?; - Ok(quote!(::std::io::println(#expanded)).into_token_stream(cx)) + Ok(quote!(::std::io::println(#expanded)).into_token_stream(cx)?) } /// Prints to output, with a newline. diff --git a/crates/rune/src/modules/iter.rs b/crates/rune/src/modules/iter.rs index a54d21fa9..521f7e742 100644 --- a/crates/rune/src/modules/iter.rs +++ b/crates/rune/src/modules/iter.rs @@ -14,7 +14,7 @@ use crate::{ContextError, Module}; /// Construct the `std::iter` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["iter"]); + let mut module = Module::with_crate_item("std", ["iter"])?; module.ty::()?; module.function_meta(next)?; diff --git a/crates/rune/src/modules/macros.rs b/crates/rune/src/modules/macros.rs index 77408e828..b86c9c514 100644 --- a/crates/rune/src/modules/macros.rs +++ b/crates/rune/src/modules/macros.rs @@ -11,7 +11,7 @@ use crate::{ContextError, Module}; /// Construct the `std::macros` module. pub fn module() -> Result { let mut builtins = - Module::with_crate_item("std", ["macros", "builtin"]).with_unique("std::macros::builtin"); + Module::with_crate_item("std", ["macros", "builtin"])?.with_unique("std::macros::builtin"); builtins.macro_meta(file)?; builtins.macro_meta(line)?; Ok(builtins) @@ -34,11 +34,12 @@ pub(crate) fn line( let mut parser = Parser::from_token_stream(stream, cx.input_span()); parser.eof()?; - Ok(quote!( + let stream = quote!( #[builtin] line!() - ) - .into_token_stream(cx)) + ); + + Ok(stream.into_token_stream(cx)?) } /// Return the name of the current file. @@ -58,9 +59,10 @@ pub(crate) fn file( let mut parser = Parser::from_token_stream(stream, cx.input_span()); parser.eof()?; - Ok(quote!( + let stream = quote!( #[builtin] file!() - ) - .into_token_stream(cx)) + ); + + Ok(stream.into_token_stream(cx)?) } diff --git a/crates/rune/src/modules/mem.rs b/crates/rune/src/modules/mem.rs index 27b3ae2bb..5f72f9ac4 100644 --- a/crates/rune/src/modules/mem.rs +++ b/crates/rune/src/modules/mem.rs @@ -6,7 +6,7 @@ use crate::{ContextError, Module}; /// Construct the `std` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["mem"]); + let mut module = Module::with_crate_item("std", ["mem"])?; module.function_meta(drop)?; Ok(module) } diff --git a/crates/rune/src/modules/num.rs b/crates/rune/src/modules/num.rs index 561796ee0..3eb4b73c3 100644 --- a/crates/rune/src/modules/num.rs +++ b/crates/rune/src/modules/num.rs @@ -6,7 +6,7 @@ use crate::{ContextError, Module}; /// Install the core package into the given functions namespace. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["num"]); + let mut module = Module::with_crate_item("std", ["num"])?; module.ty::()?; module.ty::()?; Ok(module) diff --git a/crates/rune/src/modules/object.rs b/crates/rune/src/modules/object.rs index 109eb5699..267e7cc4c 100644 --- a/crates/rune/src/modules/object.rs +++ b/crates/rune/src/modules/object.rs @@ -2,16 +2,15 @@ use core::cmp::Ordering; -use crate::no_std::prelude::*; - use crate as rune; -use crate::alloc::TryClone; +use crate::alloc::prelude::*; +use crate::alloc::Vec; use crate::runtime::{EnvProtocolCaller, Iterator, Object, Protocol, Value, VmResult}; use crate::{ContextError, Module}; /// Construct the `std::object` module. pub fn module() -> Result { - let mut m = Module::with_crate_item("std", ["object"]); + let mut m = Module::with_crate_item("std", ["object"])?; m.ty::()?; @@ -96,20 +95,17 @@ fn get(object: &Object, key: &str) -> Option { /// vec.sort(); /// assert_eq!(vec, ["a", "b", "c"]); /// ``` -#[rune::function(instance)] #[inline] -fn keys(object: &Object) -> VmResult { +#[rune::function(vm_result, instance)] +fn keys(object: &Object) -> Iterator { // TODO: implement as lazy iteration. let mut keys = Vec::new(); for key in object.keys() { - keys.push(vm_try!(key.try_clone())); + keys.try_push(key.try_clone().vm?).vm?; } - VmResult::Ok(Iterator::from_double_ended( - "std::object::Keys", - keys.into_iter(), - )) + Iterator::from_double_ended("std::object::Keys", keys.into_iter()) } /// An iterator visiting all values in arbitrary order. @@ -127,10 +123,16 @@ fn keys(object: &Object) -> VmResult { /// vec.sort(); /// assert_eq!(vec, [1, 2, 3]); /// ``` -#[rune::function(instance)] #[inline] +#[rune::function(vm_result, instance)] fn values(object: &Object) -> Iterator { - let iter = object.values().cloned().collect::>().into_iter(); + // TODO: implement as lazy iteration. + let iter = object + .values() + .cloned() + .try_collect::>() + .vm? + .into_iter(); Iterator::from_double_ended("std::object::Values", iter) } diff --git a/crates/rune/src/modules/ops.rs b/crates/rune/src/modules/ops.rs index 1c4b7f201..48ade2b9b 100644 --- a/crates/rune/src/modules/ops.rs +++ b/crates/rune/src/modules/ops.rs @@ -17,7 +17,7 @@ static STATE: OnceCell = OnceCell::new(); #[rune::module(::std::ops)] /// Overloadable operators. pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta); + let mut m = Module::from_meta(self::module_meta)?; { m.ty::()?; @@ -91,7 +91,7 @@ pub fn module() -> Result { { m.generator_state(["GeneratorState"])? - .docs(["Enum indicating the state of a generator."]); + .docs(["Enum indicating the state of a generator."])?; m.function_meta(generator_state_partial_eq)?; m.function_meta(generator_state_eq)?; diff --git a/crates/rune/src/modules/option.rs b/crates/rune/src/modules/option.rs index 77e3e686b..0858b1361 100644 --- a/crates/rune/src/modules/option.rs +++ b/crates/rune/src/modules/option.rs @@ -6,7 +6,7 @@ use crate::{ContextError, Module}; /// Construct the `std::option` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["option"]); + let mut module = Module::with_crate_item("std", ["option"])?; module.option(["Option"])?; // Sorted for ease of finding module.function_meta(expect)?; diff --git a/crates/rune/src/modules/result.rs b/crates/rune/src/modules/result.rs index 117da4d94..0055eb787 100644 --- a/crates/rune/src/modules/result.rs +++ b/crates/rune/src/modules/result.rs @@ -7,19 +7,19 @@ use crate::{ContextError, Module}; /// Construct the `std::result` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["result"]); + let mut module = Module::with_crate_item("std", ["result"])?; // Sorted for ease of finding let mut result = module .result(["Result"])? - .static_docs(&["Result is a type that represents either success (Ok) or failure (Err)."]); + .static_docs(&["Result is a type that represents either success (Ok) or failure (Err)."])?; result .variant_mut(0)? - .static_docs(&["Contains the success value"]); + .static_docs(&["Contains the success value"])?; result .variant_mut(1)? - .static_docs(&["Contains the error value"]); + .static_docs(&["Contains the error value"])?; module.function_meta(ok)?; module.function_meta(is_ok)?; diff --git a/crates/rune/src/modules/stream.rs b/crates/rune/src/modules/stream.rs index 3b6fceffb..d9fd8ee30 100644 --- a/crates/rune/src/modules/stream.rs +++ b/crates/rune/src/modules/stream.rs @@ -5,7 +5,7 @@ use crate::{ContextError, Module}; /// Construct the `std::stream` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["stream"]); + let mut module = Module::with_crate_item("std", ["stream"])?; module.ty::>()?; module.associated_function("next", Stream::::next_shared)?; module.associated_function("resume", Stream::::resume_shared)?; diff --git a/crates/rune/src/modules/string.rs b/crates/rune/src/modules/string.rs index dc66145bb..81abfcc86 100644 --- a/crates/rune/src/modules/string.rs +++ b/crates/rune/src/modules/string.rs @@ -3,24 +3,27 @@ use core::char; use core::cmp::Ordering; use core::num::{ParseFloatError, ParseIntError}; +use core::str::Utf8Error; use crate as rune; +use crate::alloc::fmt::TryWrite; +use crate::alloc::prelude::*; use crate::alloc::string::FromUtf8Error; -use crate::alloc::{String, TryClone, TryToOwned, TryWrite, Vec}; +use crate::alloc::{String, Vec}; use crate::no_std::std; use crate::runtime::{Bytes, Formatter, Iterator, Panic, Value, VmErrorKind, VmResult}; use crate::{Any, ContextError, Module}; /// Construct the `std::string` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["string"]); + let mut module = Module::with_crate_item("std", ["string"])?; module.ty::()?; module.function_meta(string_from)?; module .function_meta(string_from_str)? - .deprecated("Use String::from instead"); + .deprecated("Use String::from instead")?; module.function_meta(string_new)?; module.function_meta(string_with_capacity)?; module.function_meta(cmp)?; @@ -43,7 +46,7 @@ pub fn module() -> Result { module.function_meta(split)?; module .associated_function("split_str", __rune_fn__split)? - .deprecated("Use String::split instead"); + .deprecated("Use String::split instead")?; module.function_meta(trim)?; module.function_meta(trim_end)?; module.function_meta(replace)?; @@ -149,8 +152,8 @@ fn from_utf8(bytes: &[u8]) -> VmResult> { /// assert!(is_readable(s)); /// ``` #[rune::function(instance)] -fn as_bytes(s: &str) -> Bytes { - Bytes::from_vec(s.as_bytes().to_vec()) +fn as_bytes(s: &str) -> VmResult { + VmResult::Ok(Bytes::from_vec(vm_try!(Vec::try_from(s.as_bytes())))) } /// Constructs a string from another string. @@ -533,7 +536,7 @@ fn reserve_exact(this: &mut String, additional: usize) -> VmResult<()> { /// ``` #[rune::function(instance)] fn into_bytes(s: String) -> Bytes { - Bytes::from_vec(std::Vec::from(s.into_bytes())) + Bytes::from_vec(s.into_bytes()) } /// Checks that `index`-th byte is the first byte in a UTF-8 code point sequence @@ -1107,3 +1110,4 @@ fn parse_char(s: &str) -> Result { } crate::__internal_impl_any!(::std::string, FromUtf8Error); +crate::__internal_impl_any!(::std::string, Utf8Error); diff --git a/crates/rune/src/modules/test.rs b/crates/rune/src/modules/test.rs index 17de3f4af..4a811fd9d 100644 --- a/crates/rune/src/modules/test.rs +++ b/crates/rune/src/modules/test.rs @@ -5,6 +5,7 @@ use crate::no_std::vec::Vec; use crate as rune; +use crate::alloc::try_format; use crate::ast; use crate::compile; use crate::macros::{quote, FormatArgs, MacroContext, TokenStream}; @@ -34,7 +35,7 @@ impl Bencher { /// Construct the `std::test` module. pub fn module() -> Result { - let mut module = Module::with_crate_item("std", ["test"]).with_unique("std::test"); + let mut module = Module::with_crate_item("std", ["test"])?.with_unique("std::test"); module.macro_meta(assert)?; module.macro_meta(assert_eq)?; module.macro_meta(assert_ne)?; @@ -42,7 +43,7 @@ pub fn module() -> Result { "A type to perform benchmarks.", "", "This is the type of the argument to any function which is annotated with `#[bench]`", - ]); + ])?; module.function_meta(Bencher::iter)?; Ok(module) } @@ -84,15 +85,15 @@ pub(crate) fn assert( ::std::panic("assertion failed: " + (#expanded)); }) } else { - let message = format!("assertion failed: {}", cx.stringify(&expr)); - let message = cx.lit(&message); + let message = try_format!("assertion failed: {}", cx.stringify(&expr)?); + let message = cx.lit(&message)?; quote!(if !(#expr) { ::std::panic(#message); }) }; - Ok(output.into_token_stream(cx)) + Ok(output.into_token_stream(cx)?) } /// Assert that the two arguments provided are equal, or cause a vm panic. @@ -139,7 +140,7 @@ pub(crate) fn assert_eq( } }} } else { - let message = cx.lit("assertion failed (left == right):"); + let message = cx.lit("assertion failed (left == right):")?; quote! {{ let left = #left; @@ -154,7 +155,7 @@ pub(crate) fn assert_eq( }} }; - Ok(output.into_token_stream(cx)) + Ok(output.into_token_stream(cx)?) } /// Assert that the two arguments provided are not equal, or cause a vm panic. @@ -201,7 +202,7 @@ pub(crate) fn assert_ne( } }} } else { - let message = cx.lit("assertion failed (left != right):"); + let message = cx.lit("assertion failed (left != right):")?; quote! {{ let left = #left; @@ -216,5 +217,5 @@ pub(crate) fn assert_ne( }} }; - Ok(output.into_token_stream(cx)) + Ok(output.into_token_stream(cx)?) } diff --git a/crates/rune/src/modules/tuple.rs b/crates/rune/src/modules/tuple.rs index e6d79c79d..05e1299b1 100644 --- a/crates/rune/src/modules/tuple.rs +++ b/crates/rune/src/modules/tuple.rs @@ -11,8 +11,8 @@ use crate::{ContextError, Module}; /// Dynamic tuples. #[rune::module(::std::tuple)] pub fn module() -> Result { - let mut m = Module::from_meta(self::module_meta); - m.ty::()?.docs(["The tuple type."]); + let mut m = Module::from_meta(self::module_meta)?; + m.ty::()?.docs(["The tuple type."])?; m.function_meta(len)?; m.function_meta(is_empty)?; m.function_meta(get)?; diff --git a/crates/rune/src/modules/vec.rs b/crates/rune/src/modules/vec.rs index 45e0a3616..8ef1e05e6 100644 --- a/crates/rune/src/modules/vec.rs +++ b/crates/rune/src/modules/vec.rs @@ -3,7 +3,7 @@ use core::cmp::Ordering; use crate as rune; -use crate::alloc::TryClone; +use crate::alloc::prelude::*; #[cfg(feature = "std")] use crate::runtime::Hasher; use crate::runtime::{ @@ -14,7 +14,7 @@ use crate::{ContextError, Module}; /// Construct the `std::vec` module. pub fn module() -> Result { - let mut m = Module::with_crate_item("std", ["vec"]); + let mut m = Module::with_crate_item("std", ["vec"])?; m.ty::()?.docs([ "A dynamic vector.", @@ -30,7 +30,7 @@ pub fn module() -> Result { "assert!([1, 2, 3] < [1, 2, 4]);", "assert!([1, 2, 4] > [1, 2, 3]);", "```", - ]); + ])?; m.function_meta(vec_new)?; m.function_meta(vec_with_capacity)?; diff --git a/crates/rune/src/no_std/anyhow.rs b/crates/rune/src/no_std/anyhow.rs deleted file mode 100644 index e942c15d6..000000000 --- a/crates/rune/src/no_std/anyhow.rs +++ /dev/null @@ -1,23 +0,0 @@ -use core::fmt; - -use crate::no_std::error::Error as StdError; - -/// Type-erased error produced in no-std environments. -#[derive(Debug)] -pub struct Error {} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "An error occurred") - } -} - -impl From for Error -where - E: StdError + Send + Sync + 'static, -{ - #[cold] - fn from(_: E) -> Self { - Error {} - } -} diff --git a/crates/rune/src/no_std/mod.rs b/crates/rune/src/no_std/mod.rs index e48ff609c..e5f8ba368 100644 --- a/crates/rune/src/no_std/mod.rs +++ b/crates/rune/src/no_std/mod.rs @@ -27,13 +27,6 @@ macro_rules! alloc { } } -#[cfg(feature = "std")] -pub use ::anyhow::Error; -#[cfg(not(feature = "std"))] -pub(crate) mod anyhow; -#[cfg(not(feature = "std"))] -pub use self::anyhow::Error; - alloc! { pub(crate) use ::sync; pub(crate) use ::vec; @@ -43,8 +36,6 @@ alloc! { pub(crate) use ::string; } -pub(crate) use ::core::fmt; - pub(crate) mod std { alloc! { pub(crate) use ::boxed::Box; @@ -68,10 +59,6 @@ pub(crate) mod collections { pub(crate) use ::rust_alloc::collections::{btree_map, BTreeMap}; pub(crate) use ::rust_alloc::collections::{btree_set, BTreeSet}; pub(crate) use ::rust_alloc::collections::{vec_deque, VecDeque}; - #[cfg(not(feature = "std"))] - pub(crate) use hashbrown::{hash_map, HashMap}; - #[cfg(not(feature = "std"))] - pub(crate) use hashbrown::{hash_set, HashSet}; #[cfg(feature = "std")] pub(crate) use std::collections::{hash_map, HashMap}; #[cfg(feature = "std")] @@ -86,25 +73,3 @@ pub(crate) mod io; #[doc(inline)] pub(crate) use rune_core::error; - -#[cfg(not(feature = "std"))] -pub(crate) mod path; - -#[cfg(feature = "std")] -pub(crate) use ::std::path; - -#[cfg(not(feature = "std"))] -extern "C" { - fn __rune_abort() -> !; -} - -#[cfg(not(feature = "std"))] -pub(crate) fn abort() -> ! { - // SAFETY: hook is always safe to call. - unsafe { __rune_abort() } -} - -#[cfg(feature = "std")] -pub(crate) fn abort() -> ! { - ::std::process::abort() -} diff --git a/crates/rune/src/params.rs b/crates/rune/src/params.rs index fc9b30754..39c4a78c0 100644 --- a/crates/rune/src/params.rs +++ b/crates/rune/src/params.rs @@ -1,3 +1,6 @@ +use crate::alloc; +#[cfg(feature = "doc")] +use crate::alloc::prelude::*; use crate::hash::Hash; use crate::module::{AssociatedFunctionName, ToFieldFunction, ToInstance}; use crate::runtime::Protocol; @@ -10,15 +13,15 @@ where T: ToInstance, { #[inline] - fn to_instance(self) -> AssociatedFunctionName { - let info = self.name.to_instance(); + fn to_instance(self) -> alloc::Result { + let info = self.name.to_instance()?; - AssociatedFunctionName { + Ok(AssociatedFunctionName { associated: info.associated, function_parameters: Hash::parameters(self.parameters.iter().map(|t| t.hash)), #[cfg(feature = "doc")] - parameter_types: self.parameters.iter().map(|t| t.hash).collect(), - } + parameter_types: self.parameters.iter().map(|t| t.hash).try_collect()?, + }) } } @@ -27,14 +30,14 @@ where T: ToFieldFunction, { #[inline] - fn to_field_function(self, protocol: Protocol) -> AssociatedFunctionName { - let info = self.name.to_field_function(protocol); + fn to_field_function(self, protocol: Protocol) -> alloc::Result { + let info = self.name.to_field_function(protocol)?; - AssociatedFunctionName { + Ok(AssociatedFunctionName { associated: info.associated, function_parameters: Hash::parameters(self.parameters.iter().map(|p| p.hash)), #[cfg(feature = "doc")] - parameter_types: self.parameters.iter().map(|p| p.hash).collect(), - } + parameter_types: self.parameters.iter().map(|p| p.hash).try_collect()?, + }) } } diff --git a/crates/rune/src/parse/id.rs b/crates/rune/src/parse/id.rs index 46f64b536..8d13f38c3 100644 --- a/crates/rune/src/parse/id.rs +++ b/crates/rune/src/parse/id.rs @@ -1,12 +1,16 @@ use core::fmt; use core::num::NonZeroU32; +use crate as rune; +use crate::alloc::prelude::*; + /// A non-zero [Id] which definitely contains a value. We keep this distinct /// from `Id` to allow for safely using this as a key in a hashmap, preventing /// us from inadvertently storing an empty identifier. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Hash)] +#[try_clone(copy)] #[repr(transparent)] -pub struct NonZeroId(NonZeroU32); +pub struct NonZeroId(#[try_clone(copy)] NonZeroU32); impl fmt::Display for NonZeroId { #[inline] @@ -26,7 +30,8 @@ impl From for NonZeroId { /// The default implementation for an identifier is empty, meaning it does not /// hold any value. Attempting to perform lookups over it will fail with an /// error indicating that it's empty with the formatted string `Id(*)`. -#[derive(Clone, Copy, Default, PartialEq, Eq)] +#[derive(TryClone, Clone, Copy, Default, PartialEq, Eq)] +#[try_clone(copy)] #[repr(transparent)] pub struct Id(Option); diff --git a/crates/rune/src/parse/parse.rs b/crates/rune/src/parse/parse.rs index 020c7b265..51569cb6e 100644 --- a/crates/rune/src/parse/parse.rs +++ b/crates/rune/src/parse/parse.rs @@ -1,5 +1,4 @@ -use crate::no_std::prelude::*; - +use crate::alloc::{Box, Vec}; use crate::compile; use crate::parse::{Parser, Peek}; @@ -48,7 +47,7 @@ where { #[inline] fn parse(parser: &mut Parser) -> compile::Result { - Ok(Box::new(parser.parse()?)) + Ok(Box::try_new(parser.parse()?)?) } } @@ -62,7 +61,7 @@ where let mut output = Vec::new(); while parser.peek::()? { - output.push(parser.parse()?); + output.try_push(parser.parse()?)?; } Ok(output) diff --git a/crates/rune/src/parse/parser.rs b/crates/rune/src/parse/parser.rs index c0f1d40fe..ad6ffa6b0 100644 --- a/crates/rune/src/parse/parser.rs +++ b/crates/rune/src/parse/parser.rs @@ -20,7 +20,7 @@ use crate::SourceId; /// /// let mut parser = Parser::new("fn foo() {}", SourceId::empty(), false); /// let ast = parser.parse::()?; -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Debug)] pub struct Parser<'a> { diff --git a/crates/rune/src/parse/peek.rs b/crates/rune/src/parse/peek.rs index 13a35b7a6..fac28500b 100644 --- a/crates/rune/src/parse/peek.rs +++ b/crates/rune/src/parse/peek.rs @@ -1,5 +1,4 @@ -use crate::no_std::prelude::*; - +use crate::alloc::Box; use crate::parse::{Parse, Peeker}; /// Implemented by tokens that can be peeked for. diff --git a/crates/rune/src/query.rs b/crates/rune/src/query.rs index 64a2a7a5d..e824eb3a8 100644 --- a/crates/rune/src/query.rs +++ b/crates/rune/src/query.rs @@ -6,12 +6,12 @@ mod query; use core::fmt; use core::num::NonZeroUsize; -use crate::no_std::path::PathBuf; -use crate::no_std::prelude::*; - pub(crate) use self::query::{MissingId, Query, QueryInner}; use crate as rune; +use crate::alloc::path::PathBuf; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, Vec}; use crate::ast; use crate::ast::{Span, Spanned}; use crate::compile::ir; @@ -23,7 +23,8 @@ use crate::parse::NonZeroId; use crate::runtime::format; /// Indication whether a value is being evaluated because it's being used or not. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) enum Used { /// The value is not being used. Unused, @@ -108,21 +109,23 @@ pub(crate) struct BuiltInFormat { } /// Macro data for `file!()` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] pub(crate) struct BuiltInFile { /// Path value to use pub(crate) value: ast::Lit, } /// Macro data for `line!()` -#[derive(Debug, Clone, Copy, PartialEq, Eq, Spanned)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, Spanned)] +#[try_clone(copy)] pub(crate) struct BuiltInLine { /// The line number pub(crate) value: ast::Lit, } /// An entry in the build queue. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) enum Build { Function(indexing::Function), Closure(indexing::Closure), @@ -136,7 +139,7 @@ pub(crate) enum Build { } /// An entry in the build queue. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct BuildEntry { /// The item of the build entry. pub(crate) item_meta: ItemMeta, @@ -166,7 +169,8 @@ pub(crate) struct ItemImplEntry { } /// Query information for a path. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, TryClone, Clone, Copy)] +#[try_clone(copy)] pub(crate) struct QueryPath { pub(crate) module: ModId, pub(crate) impl_item: Option, @@ -196,8 +200,8 @@ impl GenericsParameters { self.parameters.iter().all(|p| p.is_none()) } - pub(crate) fn as_boxed(&self) -> Box<[Option]> { - self.parameters.iter().copied().collect() + pub(crate) fn as_boxed(&self) -> alloc::Result]>> { + self.parameters.iter().copied().try_collect() } } diff --git a/crates/rune/src/query/query.rs b/crates/rune/src/query/query.rs index 7a11b4b1a..8439aa3e0 100644 --- a/crates/rune/src/query/query.rs +++ b/crates/rune/src/query/query.rs @@ -2,13 +2,13 @@ use core::fmt; #[cfg(feature = "emit")] use core::mem::take; -use crate::no_std::borrow::Cow; -use crate::no_std::collections::{hash_map, BTreeMap, HashMap, HashSet, VecDeque}; -use crate::no_std::prelude::*; use crate::no_std::rc::Rc; use crate::no_std::sync::Arc; -use crate::alloc::AllocError; +use crate::alloc::borrow::Cow; +use crate::alloc::prelude::*; +use crate::alloc::{self, try_format, try_vec, BTreeMap, Box, HashSet, Vec, VecDeque}; +use crate::alloc::{hash_map, HashMap}; use crate::ast::{Span, Spanned}; use crate::compile::context::ContextMeta; use crate::compile::ir; @@ -200,8 +200,9 @@ impl<'a, 'arena> Query<'a, 'arena> { } /// Set the given meta item as used. - pub(crate) fn set_used(&mut self, item_meta: &ItemMeta) { - self.inner.used.insert(item_meta.id); + pub(crate) fn set_used(&mut self, item_meta: &ItemMeta) -> alloc::Result<()> { + self.inner.used.try_insert(item_meta.id)?; + Ok(()) } /// Get the next impl item in queue to process. @@ -221,7 +222,7 @@ impl<'a, 'arena> Query<'a, 'arena> { item: ItemId, metas: impl Iterator + Clone, parameters: &GenericsParameters, - ) -> Result, Box> { + ) -> Result, rust_alloc::boxed::Box> { #[derive(Debug, PartialEq, Eq, Clone, Copy)] enum Kind { None, @@ -311,11 +312,15 @@ impl<'a, 'arena> Query<'a, 'arena> { return Ok(ContextMatch::None); } - Err(Box::new(ErrorKind::AmbiguousContextItem { - item: self.pool.item(item).to_owned(), - #[cfg(feature = "emit")] - infos: metas.map(|i| i.info()).collect(), - })) + Err(rust_alloc::boxed::Box::new( + ErrorKind::AmbiguousContextItem { + item: self.pool.item(item).try_to_owned()?, + #[cfg(feature = "emit")] + infos: metas + .map(|i| i.info()) + .try_collect::>()??, + }, + )) } /// Access the meta for the given language item. @@ -331,7 +336,8 @@ impl<'a, 'arena> Query<'a, 'arena> { if let Some(meta) = self.query_meta(location.as_spanned(), item, Default::default())? { tracing::trace!("found in query: {:?}", meta); self.visitor - .visit_meta(location, meta.as_meta_ref(self.pool)); + .visit_meta(location, meta.as_meta_ref(self.pool)) + .with_span(location.as_spanned())?; return Ok(Some(meta)); } } @@ -345,7 +351,7 @@ impl<'a, 'arena> Query<'a, 'arena> { .with_span(location.as_spanned())? { ContextMatch::None => return Ok(None), - ContextMatch::Meta(meta) => return Ok(Some(meta.clone())), + ContextMatch::Meta(meta) => return Ok(Some(meta.try_clone()?)), ContextMatch::Context(meta, parameters) => (meta, parameters), }; @@ -362,22 +368,23 @@ impl<'a, 'arena> Query<'a, 'arena> { item_meta: ItemMeta { id: self.gen.next(), location: Default::default(), - item: self.pool.alloc_item(item), + item: self.pool.alloc_item(item)?, visibility: Default::default(), module: Default::default(), }, - kind: meta.kind.clone(), + kind: meta.kind.try_clone()?, source: None, parameters, }; - self.insert_meta(meta.clone()) + self.insert_meta(meta.try_clone()?) .with_span(location.as_spanned())?; tracing::trace!(?meta, "Found in context"); self.visitor - .visit_meta(location, meta.as_meta_ref(self.pool)); + .visit_meta(location, meta.as_meta_ref(self.pool)) + .with_span(location.as_spanned())?; Ok(Some(meta)) } @@ -397,12 +404,12 @@ impl<'a, 'arena> Query<'a, 'arena> { let kind = if !parameters.parameters.is_empty() { ErrorKind::MissingItemParameters { - item: self.pool.item(item).to_owned(), - parameters: parameters.as_boxed(), + item: self.pool.item(item).try_to_owned()?, + parameters: parameters.as_boxed()?, } } else { ErrorKind::MissingItem { - item: self.pool.item(item).to_owned(), + item: self.pool.item(item).try_to_owned()?, } }; @@ -415,21 +422,21 @@ impl<'a, 'arena> Query<'a, 'arena> { module: ModId, impl_item: Option, item: &Item, - ) -> NonZeroId { - let item = self.pool.alloc_item(item); + ) -> alloc::Result { + let item = self.pool.alloc_item(item)?; let id = self.gen.next(); - let old = self.inner.query_paths.insert( + let old = self.inner.query_paths.try_insert( id, QueryPath { module, impl_item, item, }, - ); + )?; debug_assert!(old.is_none(), "should use a unique identifier"); - id + Ok(id) } /// Insert module and associated metadata. @@ -449,7 +456,7 @@ impl<'a, 'arena> Query<'a, 'arena> { item: item.item, visibility, parent: Some(parent), - }); + })?; self.index_and_build(indexing::Entry { item_meta: item, @@ -474,9 +481,9 @@ impl<'a, 'arena> Query<'a, 'arena> { item: ItemId::default(), visibility: Visibility::Public, parent: None, - }); + })?; - self.inner.items.insert( + self.inner.items.try_insert( item_id, ItemMeta { id: item_id, @@ -485,7 +492,7 @@ impl<'a, 'arena> Query<'a, 'arena> { visibility: Visibility::Public, module, }, - ); + )?; self.insert_name(ItemId::default()).with_span(span)?; Ok(module) @@ -504,7 +511,7 @@ impl<'a, 'arena> Query<'a, 'arena> { docs: &[Doc], ) -> compile::Result { let id = items.id().with_span(location.as_spanned())?; - let item = self.pool.alloc_item(items.item()); + let item = self.pool.alloc_item(items.item())?; self.insert_new_item_with(id, item, location, module, visibility, docs) } @@ -520,13 +527,13 @@ impl<'a, 'arena> Query<'a, 'arena> { hash_map::Entry::Occupied(e) => { return Err(MetaError::new( compile::error::MetaErrorKind::MetaConflict { - current: meta.info(self.pool), - existing: e.get().info(self.pool), + current: meta.info(self.pool)?, + existing: e.get().info(self.pool)?, parameters: meta.parameters, }, )); } - hash_map::Entry::Vacant(e) => e.insert(meta), + hash_map::Entry::Vacant(e) => e.try_insert(meta)?, }; Ok(&meta.item_meta) @@ -550,12 +557,14 @@ impl<'a, 'arena> Query<'a, 'arena> { let cx = resolve_context!(self); for doc in docs { - self.visitor.visit_doc_comment( - &DynLocation::new(location.source_id, &doc.span), - self.pool.item(item), - self.pool.item_type_hash(item), - doc.doc_string.resolve(cx)?.as_ref(), - ); + self.visitor + .visit_doc_comment( + &DynLocation::new(location.source_id, &doc.span), + self.pool.item(item), + self.pool.item_type_hash(item), + doc.doc_string.resolve(cx)?.as_ref(), + ) + .with_span(location)?; } } @@ -567,7 +576,7 @@ impl<'a, 'arena> Query<'a, 'arena> { visibility, }; - self.inner.items.insert(id, item_meta); + self.inner.items.try_insert(id, item_meta)?; Ok(item_meta) } @@ -579,7 +588,7 @@ impl<'a, 'arena> Query<'a, 'arena> { let id = self.gen.next(); self.inner .internal_macros - .insert(id, Arc::new(internal_macro)); + .try_insert(id, Arc::new(internal_macro))?; Ok(id) } @@ -644,8 +653,8 @@ impl<'a, 'arena> Query<'a, 'arena> { self.inner .indexed .entry(entry.item_meta.item) - .or_default() - .push(entry); + .or_try_default()? + .try_push(entry)?; Ok(()) } @@ -653,12 +662,12 @@ impl<'a, 'arena> Query<'a, 'arena> { /// Same as `index`, but also queues the indexed entry up for building. #[tracing::instrument(skip_all)] pub(crate) fn index_and_build(&mut self, entry: indexing::Entry) -> compile::Result<()> { - self.set_used(&entry.item_meta); + self.set_used(&entry.item_meta)?; - self.inner.queue.push_back(BuildEntry { + self.inner.queue.try_push_back(BuildEntry { item_meta: entry.item_meta, build: Build::Query, - }); + })?; self.index(entry)?; Ok(()) @@ -676,7 +685,7 @@ impl<'a, 'arena> Query<'a, 'arena> { self.index(indexing::Entry { item_meta, indexed: Indexed::ConstExpr(indexing::ConstExpr { - ast: Box::new(ast.clone()), + ast: Box::try_new(ast.try_clone()?)?, }), })?; @@ -695,7 +704,7 @@ impl<'a, 'arena> Query<'a, 'arena> { self.index(indexing::Entry { item_meta, indexed: Indexed::ConstBlock(indexing::ConstBlock { - ast: Box::new(ast.clone()), + ast: Box::try_new(ast.try_clone()?)?, }), })?; @@ -787,7 +796,8 @@ impl<'a, 'arena> Query<'a, 'arena> { path: self .sources .path(item_meta.location.source_id) - .map(Into::into), + .map(|p| p.try_into()) + .transpose()?, }; let meta = meta::Meta { @@ -810,8 +820,9 @@ impl<'a, 'arena> Query<'a, 'arena> { #[tracing::instrument(skip_all)] pub(crate) fn queue_unused_entries( &mut self, - ) -> compile::Result { - tracing::trace!("queue unused"); + errors: &mut Vec<(SourceId, compile::Error)>, + ) -> alloc::Result { + tracing::trace!("Queue unused"); let unused = self .inner @@ -819,19 +830,19 @@ impl<'a, 'arena> Query<'a, 'arena> { .values() .flat_map(|entries| entries.iter()) .map(|e| (e.item_meta.location, e.item_meta.item)) - .collect::>(); + .try_collect::>()?; if unused.is_empty() { - return Ok(false); + return Ok(true); } for (location, item) in unused { - let _ = self - .query_indexed_meta(&location, item, Used::Unused) - .map_err(|e| (location.source_id, e))?; + if let Err(error) = self.query_indexed_meta(&location, item, Used::Unused) { + errors.try_push((location.source_id, error))?; + } } - Ok(true) + Ok(false) } /// Explicitly look for meta with the given item and hash. @@ -854,7 +865,7 @@ impl<'a, 'arena> Query<'a, 'arena> { // `queue_unused_entries` might end up spinning indefinitely since // it will never be exhausted. debug_assert!(!self.inner.indexed.contains_key(&item)); - return Ok(Some(meta.clone())); + return Ok(Some(meta.try_clone()?)); } self.query_indexed_meta(span, item, used) @@ -873,7 +884,7 @@ impl<'a, 'arena> Query<'a, 'arena> { if let Some(entry) = self.remove_indexed(span, item)? { let meta = self.build_indexed_entry(span, entry, used)?; self.unit.insert_meta(span, &meta, self.pool, self.inner)?; - self.insert_meta(meta.clone()).with_span(span)?; + self.insert_meta(meta.try_clone()?).with_span(span)?; tracing::trace!(item = ?item, meta = ?meta, "build"); return Ok(Some(meta)); } @@ -912,7 +923,7 @@ impl<'a, 'arena> Query<'a, 'arena> { else { return Err(compile::Error::msg( path, - format_args!("Missing query path for id {}", id), + try_format!("Missing query path for id {}", id), )); }; @@ -921,7 +932,7 @@ impl<'a, 'arena> Query<'a, 'arena> { let item = match (&path.global, &path.first) { (Some(..), ast::PathSegment::Ident(ident)) => self .pool - .alloc_item(ItemBuf::with_crate(ident.resolve(resolve_context!(self))?)), + .alloc_item(ItemBuf::with_crate(ident.resolve(resolve_context!(self))?)?)?, (Some(span), _) => { return Err(compile::Error::new(span, ErrorKind::UnsupportedGlobal)); } @@ -932,7 +943,7 @@ impl<'a, 'arena> Query<'a, 'arena> { ast::PathSegment::Super(..) => { let Some(segment) = self .pool - .try_map_alloc(self.pool.module(module).item, Item::parent) + .try_map_alloc(self.pool.module(module).item, Item::parent)? else { return Err(compile::Error::new(segment, ErrorKind::UnsupportedSuper)); }; @@ -971,7 +982,7 @@ impl<'a, 'arena> Query<'a, 'arena> { }, }; - let mut item = self.pool.item(item).to_owned(); + let mut item = self.pool.item(item).try_to_owned()?; let mut trailing = 0; let mut parameters: [Option<(&dyn Spanned, _)>; 2] = [None, None]; @@ -981,7 +992,7 @@ impl<'a, 'arena> Query<'a, 'arena> { for (_, segment) in it.by_ref() { match segment { ast::PathSegment::Ident(ident) => { - item.push(ident.resolve(resolve_context!(self))?); + item.push(ident.resolve(resolve_context!(self))?)?; } ast::PathSegment::Super(span) => { if in_self_type { @@ -991,7 +1002,7 @@ impl<'a, 'arena> Query<'a, 'arena> { )); } - if item.pop().is_none() { + if item.pop()?.is_none() { return Err(compile::Error::new(segment, ErrorKind::UnsupportedSuper)); } } @@ -1023,7 +1034,7 @@ impl<'a, 'arena> Query<'a, 'arena> { }; trailing += 1; - item.push(ident.resolve(resolve_context!(self))?); + item.push(ident.resolve(resolve_context!(self))?)?; let Some(p) = parameters_it.next() else { return Err(compile::Error::new(segment, ErrorKind::UnsupportedGenerics)); @@ -1038,7 +1049,7 @@ impl<'a, 'arena> Query<'a, 'arena> { it.next(); } - let item = self.pool.alloc_item(item); + let item = self.pool.alloc_item(item)?; if let Some(new) = self.import(path, module, item, import_used, used)? { return Ok(Named { @@ -1087,8 +1098,8 @@ impl<'a, 'arena> Query<'a, 'arena> { )); }; - let item = self.pool.alloc_item(at.extended(last)); - let target = self.pool.alloc_item(target); + let item = self.pool.alloc_item(at.extended(last)?)?; + let target = self.pool.alloc_item(target)?; let entry = meta::Import { location: location.location(), @@ -1101,12 +1112,12 @@ impl<'a, 'arena> Query<'a, 'arena> { // toplevel public uses are re-exported. if item_meta.is_public(self.pool) { - self.inner.used.insert(item_meta.id); + self.inner.used.try_insert(item_meta.id)?; - self.inner.queue.push_back(BuildEntry { + self.inner.queue.try_push_back(BuildEntry { item_meta, build: Build::ReExport, - }); + })?; } self.index(indexing::Entry { @@ -1118,7 +1129,7 @@ impl<'a, 'arena> Query<'a, 'arena> { } /// Check if unit contains the given name by prefix. - pub(crate) fn contains_prefix(&self, item: &Item) -> bool { + pub(crate) fn contains_prefix(&self, item: &Item) -> alloc::Result { self.inner.names.contains_prefix(item) } @@ -1126,7 +1137,7 @@ impl<'a, 'arena> Query<'a, 'arena> { pub(crate) fn iter_components<'it, I: 'it>( &'it self, iter: I, - ) -> impl Iterator> + 'it + ) -> alloc::Result> + 'it> where I: IntoIterator, I::Item: IntoComponent, @@ -1146,7 +1157,7 @@ impl<'a, 'arena> Query<'a, 'arena> { ) -> compile::Result> { let mut visited = HashSet::::new(); let mut path = Vec::new(); - let mut item = self.pool.item(item).to_owned(); + let mut item = self.pool.item(item).try_to_owned()?; let mut any_matched = false; let mut count = 0usize; @@ -1165,9 +1176,9 @@ impl<'a, 'arena> Query<'a, 'arena> { let mut it = item.iter(); while let Some(c) = it.next() { - cur.push(c); + cur.push(c)?; - let cur = self.pool.alloc_item(&cur); + let cur = self.pool.alloc_item(&cur)?; let update = self.import_step( span, @@ -1184,15 +1195,15 @@ impl<'a, 'arena> Query<'a, 'arena> { // Imports are *always* used once they pass this step. if let Used::Used = import_used { - self.set_used(&item_meta); + self.set_used(&item_meta)?; } - path.push(ImportStep { + path.try_push(ImportStep { location: update.location, - item: self.pool.item(update.target).to_owned(), - }); + item: self.pool.item(update.target).try_to_owned()?, + })?; - if !visited.insert(self.pool.alloc_item(&item)) { + if !visited.try_insert(self.pool.alloc_item(&item)?)? { return Err(compile::Error::new( span, ErrorKind::ImportCycle { @@ -1203,7 +1214,7 @@ impl<'a, 'arena> Query<'a, 'arena> { } module = update.module; - item = self.pool.item(update.target).join(it); + item = self.pool.item(update.target).join(it)?; any_matched = true; continue 'outer; } @@ -1212,7 +1223,7 @@ impl<'a, 'arena> Query<'a, 'arena> { } if any_matched { - return Ok(Some(self.pool.alloc_item(item))); + return Ok(Some(self.pool.alloc_item(item)?)); } Ok(None) @@ -1290,11 +1301,11 @@ impl<'a, 'arena> Query<'a, 'arena> { ast::Fields::Empty => meta::Fields::Empty, ast::Fields::Unnamed(tuple) => meta::Fields::Unnamed(tuple.len()), ast::Fields::Named(st) => { - let mut fields = HashMap::with_capacity(st.len()); + let mut fields = HashMap::try_with_capacity(st.len())?; for (position, (ast::Field { name, .. }, _)) in st.iter().enumerate() { let name = name.resolve(cx)?; - fields.insert(name.into(), FieldMeta { position }); + fields.try_insert(name.try_into()?, FieldMeta { position })?; } meta::Fields::Named(meta::FieldsNamed { fields }) @@ -1305,7 +1316,7 @@ impl<'a, 'arena> Query<'a, 'arena> { let indexing::Entry { item_meta, indexed } = entry; if let Used::Used = used { - self.inner.used.insert(item_meta.id); + self.inner.used.try_insert(item_meta.id)?; } let kind = match indexed { @@ -1319,7 +1330,7 @@ impl<'a, 'arena> Query<'a, 'arena> { let Some(enum_meta) = self.query_meta(span, enum_.item, Default::default())? else { return Err(compile::Error::msg( span, - format_args!("Missing enum by {:?}", variant.enum_id), + try_format!("Missing enum by {:?}", variant.enum_id), )); }; @@ -1331,7 +1342,7 @@ impl<'a, 'arena> Query<'a, 'arena> { } } Indexed::Struct(st) => meta::Kind::Struct { - fields: convert_fields(resolve_context!(self), st.ast.body)?, + fields: convert_fields(resolve_context!(self), Box::into_inner(st.ast).body)?, constructor: None, parameters: Hash::EMPTY, }, @@ -1340,7 +1351,7 @@ impl<'a, 'arena> Query<'a, 'arena> { associated: match (f.is_instance, &f.ast) { (true, FunctionAst::Item(ast)) => { let name: Cow = - Cow::Owned(ast.name.resolve(resolve_context!(self))?.into()); + Cow::Owned(ast.name.resolve(resolve_context!(self))?.try_into()?); Some(meta::AssociatedKind::Instance(name)) } _ => None, @@ -1357,7 +1368,7 @@ impl<'a, 'arena> Query<'a, 'arena> { #[cfg(feature = "doc")] return_type: None, #[cfg(feature = "doc")] - argument_types: Box::from([]), + argument_types: Box::default(), }, parameters: Hash::EMPTY, #[cfg(feature = "doc")] @@ -1380,10 +1391,10 @@ impl<'a, 'arena> Query<'a, 'arena> { parameter_types: Vec::new(), }; - self.inner.queue.push_back(BuildEntry { + self.inner.queue.try_push_back(BuildEntry { item_meta, build: Build::Function(f), - }); + })?; kind } @@ -1394,7 +1405,7 @@ impl<'a, 'arena> Query<'a, 'arena> { &arena, self.borrow(), item_meta.location.source_id, - ); + )?; let hir = crate::hir::lowering::expr(&mut hir_ctx, &c.ast)?; let mut cx = ir::Ctxt { @@ -1406,7 +1417,7 @@ impl<'a, 'arena> Query<'a, 'arena> { let mut const_compiler = ir::Interpreter { budget: ir::Budget::new(1_000_000), - scopes: Default::default(), + scopes: ir::Scopes::new()?, module: item_meta.module, item: item_meta.item, q: self.borrow(), @@ -1415,13 +1426,13 @@ impl<'a, 'arena> Query<'a, 'arena> { let const_value = const_compiler.eval_const(&ir, used)?; let hash = self.pool.item_type_hash(item_meta.item); - self.inner.constants.insert(hash, const_value); + self.inner.constants.try_insert(hash, const_value)?; if used.is_unused() { - self.inner.queue.push_back(BuildEntry { + self.inner.queue.try_push_back(BuildEntry { item_meta, build: Build::Unused, - }); + })?; } meta::Kind::Const @@ -1433,7 +1444,7 @@ impl<'a, 'arena> Query<'a, 'arena> { &arena, self.borrow(), item_meta.location.source_id, - ); + )?; let hir = crate::hir::lowering::block(&mut hir_ctx, &c.ast)?; let mut cx = ir::Ctxt { @@ -1445,7 +1456,7 @@ impl<'a, 'arena> Query<'a, 'arena> { let mut const_compiler = ir::Interpreter { budget: ir::Budget::new(1_000_000), - scopes: Default::default(), + scopes: ir::Scopes::new()?, module: item_meta.module, item: item_meta.item, q: self.borrow(), @@ -1454,13 +1465,13 @@ impl<'a, 'arena> Query<'a, 'arena> { let const_value = const_compiler.eval_const(&ir, used)?; let hash = self.pool.item_type_hash(item_meta.item); - self.inner.constants.insert(hash, const_value); + self.inner.constants.try_insert(hash, const_value)?; if used.is_unused() { - self.inner.queue.push_back(BuildEntry { + self.inner.queue.try_push_back(BuildEntry { item_meta, build: Build::Unused, - }); + })?; } meta::Kind::Const @@ -1472,7 +1483,7 @@ impl<'a, 'arena> Query<'a, 'arena> { self.const_arena, self.borrow(), item_meta.location.source_id, - ); + )?; let hir = crate::hir::lowering::item_fn(&mut cx, &c.item_fn)?; let mut cx = ir::Ctxt { @@ -1484,30 +1495,30 @@ impl<'a, 'arena> Query<'a, 'arena> { let id = self.gen.next(); - self.inner.const_fns.insert( + self.inner.const_fns.try_insert( id, Rc::new(ConstFn { item_meta, ir_fn, hir, }), - ); + )?; if used.is_unused() { - self.inner.queue.push_back(BuildEntry { + self.inner.queue.try_push_back(BuildEntry { item_meta, build: Build::Unused, - }); + })?; } meta::Kind::ConstFn { id } } Indexed::Import(import) => { if !import.wildcard { - self.inner.queue.push_back(BuildEntry { + self.inner.queue.try_push_back(BuildEntry { item_meta, build: Build::Import(import), - }); + })?; } meta::Kind::Import(import.entry) @@ -1520,7 +1531,8 @@ impl<'a, 'arena> Query<'a, 'arena> { path: self .sources .path(item_meta.location.source_id) - .map(Into::into), + .map(|p| p.try_into()) + .transpose()?, }; Ok(meta::Meta { @@ -1534,7 +1546,7 @@ impl<'a, 'arena> Query<'a, 'arena> { } /// Insert the given name into the unit. - fn insert_name(&mut self, item: ItemId) -> Result<(), AllocError> { + fn insert_name(&mut self, item: ItemId) -> alloc::Result<()> { let item = self.pool.item(item); self.inner.names.insert(item)?; Ok(()) @@ -1566,26 +1578,24 @@ impl<'a, 'arena> Query<'a, 'arena> { item: ItemId, ) -> compile::Result> { // See if there's an index entry we can construct and insert. - let entries = match self.inner.indexed.remove(&item) { - Some(entries) => entries, - None => return Ok(None), + let Some(entries) = self.inner.indexed.remove(&item) else { + return Ok(None); }; let mut it = entries.into_iter().peekable(); - let mut cur = match it.next() { - Some(first) => first, - None => return Ok(None), + let Some(mut cur) = it.next() else { + return Ok(None); }; if it.peek().is_none() { return Ok(Some(cur)); } - let mut locations = vec![(cur.item_meta.location, cur.item().to_owned())]; + let mut locations = try_vec![(cur.item_meta.location, cur.item())]; while let Some(oth) = it.next() { - locations.push((oth.item_meta.location, oth.item().to_owned())); + locations.try_push((oth.item_meta.location, oth.item()))?; if let (Indexed::Import(a), Indexed::Import(b)) = (&cur.indexed, &oth.indexed) { if a.wildcard { @@ -1599,18 +1609,18 @@ impl<'a, 'arena> Query<'a, 'arena> { } for oth in it { - locations.push((oth.item_meta.location, oth.item().to_owned())); + locations.try_push((oth.item_meta.location, oth.item()))?; } return Err(compile::Error::new( span, ErrorKind::AmbiguousItem { - item: self.pool.item(cur.item_meta.item).to_owned(), + item: self.pool.item(cur.item_meta.item).try_to_owned()?, #[cfg(feature = "emit")] locations: locations .into_iter() - .map(|(loc, item)| (loc, self.pool.item(item).to_owned())) - .collect(), + .map(|(loc, item)| Ok((loc, self.pool.item(item).try_to_owned()?))) + .try_collect::>()??, }, )); } @@ -1619,12 +1629,12 @@ impl<'a, 'arena> Query<'a, 'arena> { return Err(compile::Error::new( span, ErrorKind::AmbiguousItem { - item: self.pool.item(cur.item_meta.item).to_owned(), + item: self.pool.item(cur.item_meta.item).try_to_owned()?, #[cfg(feature = "emit")] locations: locations .into_iter() - .map(|(loc, item)| (loc, self.pool.item(item).to_owned())) - .collect(), + .map(|(loc, item)| Ok((loc, self.pool.item(item).try_to_owned()?))) + .try_collect::>()??, }, )); } @@ -1641,18 +1651,17 @@ impl<'a, 'arena> Query<'a, 'arena> { local: &ast::Ident, used: Used, ) -> compile::Result { - let mut base = self.pool.item(item).to_owned(); + let mut base = self.pool.item(item).try_to_owned()?; debug_assert!(base.starts_with(self.pool.module_item(module))); - let local_str = local.resolve(resolve_context!(self))?.to_owned(); + let local_str = local.resolve(resolve_context!(self))?.try_to_owned()?; while base.starts_with(self.pool.module_item(module)) { - base.push(&local_str); - + base.push(&local_str)?; tracing::trace!(?base, "testing"); - if self.inner.names.contains(&base) { - let item = self.pool.alloc_item(&base); + if self.inner.names.contains(&base)? { + let item = self.pool.alloc_item(&base)?; // TODO: We probably should not engage the whole query meta // machinery here. @@ -1664,29 +1673,29 @@ impl<'a, 'arena> Query<'a, 'arena> { .. } ) { - return Ok(self.pool.alloc_item(base)); + return Ok(self.pool.alloc_item(base)?); } } } - let c = base.pop(); + let c = base.pop()?; debug_assert!(c.is_some()); - if base.pop().is_none() { + if base.pop()?.is_none() { break; } } if let Some(item) = self.prelude.get(&local_str) { - return Ok(self.pool.alloc_item(item)); + return Ok(self.pool.alloc_item(item)?); } if self.context.contains_crate(&local_str) { - return Ok(self.pool.alloc_item(ItemBuf::with_crate(&local_str))); + return Ok(self.pool.alloc_item(ItemBuf::with_crate(&local_str)?)?); } - let new_module = self.pool.module_item(module).extended(&local_str); - Ok(self.pool.alloc_item(new_module)) + let new_module = self.pool.module_item(module).extended(&local_str)?; + Ok(self.pool.alloc_item(new_module)?) } /// Check that the given item is accessible from the given module. @@ -1701,41 +1710,42 @@ impl<'a, 'arena> Query<'a, 'arena> { #[cfg(feature = "emit")] chain: &mut Vec, ) -> compile::Result<()> { #[cfg(feature = "emit")] - fn into_chain(chain: Vec) -> Vec { - chain.into_iter().map(|c| c.location).collect() + fn into_chain(chain: Vec) -> alloc::Result> { + chain.into_iter().map(|c| c.location).try_collect() } let (common, tree) = self .pool .module_item(from) - .ancestry(self.pool.module_item(module)); - let mut current_module = common.clone(); + .ancestry(self.pool.module_item(module))?; + + let mut current_module = common.try_clone()?; // Check each module from the common ancestrly to the module. for c in &tree { - current_module.push(c); - let current_module_id = self.pool.alloc_item(¤t_module); + current_module.push(c)?; + let current_module_id = self.pool.alloc_item(¤t_module)?; - let m = self.pool.module_by_item(current_module_id).ok_or_else(|| { - compile::Error::new( + let Some(m) = self.pool.module_by_item(current_module_id) else { + return Err(compile::Error::new( span, ErrorKind::MissingMod { - item: current_module.clone(), + item: current_module.try_clone()?, }, - ) - })?; + )); + }; if !m.visibility.is_visible(&common, ¤t_module) { return Err(compile::Error::new( span, ErrorKind::NotVisibleMod { #[cfg(feature = "emit")] - chain: into_chain(take(chain)), + chain: into_chain(take(chain))?, #[cfg(feature = "emit")] location: m.location, visibility: m.visibility, item: current_module, - from: self.pool.module_item(from).to_owned(), + from: self.pool.module_item(from).try_to_owned()?, }, )); } @@ -1746,12 +1756,12 @@ impl<'a, 'arena> Query<'a, 'arena> { span, ErrorKind::NotVisible { #[cfg(feature = "emit")] - chain: into_chain(take(chain)), + chain: into_chain(take(chain))?, #[cfg(feature = "emit")] location, visibility, - item: self.pool.item(item).to_owned(), - from: self.pool.module_item(from).to_owned(), + item: self.pool.item(item).try_to_owned()?, + from: self.pool.module_item(from).try_to_owned()?, }, )); } @@ -1769,12 +1779,18 @@ impl<'a, 'arena> Query<'a, 'arena> { } /// Insert captures. - pub(crate) fn insert_captures<'hir, C>(&mut self, hash: Hash, captures: C) + pub(crate) fn insert_captures<'hir, C>(&mut self, hash: Hash, captures: C) -> alloc::Result<()> where C: IntoIterator>, { - let captures = captures.into_iter().map(hir::Name::into_owned); - self.inner.captures.insert(hash, captures.collect()); + let captures = captures + .into_iter() + .map(hir::Name::into_owned) + .try_collect::>()??; + + self.inner.captures.try_insert(hash, captures)?; + + Ok(()) } /// Get captures for the given hash. diff --git a/crates/rune/src/runtime/access.rs b/crates/rune/src/runtime/access.rs index b07f39f93..aaf24efb3 100644 --- a/crates/rune/src/runtime/access.rs +++ b/crates/rune/src/runtime/access.rs @@ -241,7 +241,7 @@ impl Access { let state = self.get(); if state == MAX_USES { - crate::no_std::abort(); + crate::alloc::abort(); } let n = state.wrapping_sub(1); @@ -385,7 +385,7 @@ impl<'a, T: ?Sized> BorrowRef<'a, T> { /// let value: BorrowRef<[u32]> = BorrowRef::map(vec, |vec| &vec[0..2]); /// /// assert_eq!(&*value, &[1u32, 2u32][..]); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn map(this: Self, m: M) -> BorrowRef<'a, U> where @@ -409,7 +409,7 @@ impl<'a, T: ?Sized> BorrowRef<'a, T> { /// let mut value: Option> = BorrowRef::try_map(vec, |vec| vec.get(0..2)); /// /// assert_eq!(value.as_deref(), Some(&[1u32, 2u32][..])); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn try_map(this: Self, m: M) -> Option> where @@ -523,7 +523,7 @@ impl<'a, T: ?Sized> BorrowMut<'a, T> { /// let value: BorrowMut<[u32]> = BorrowMut::map(vec, |vec| &mut vec[0..2]); /// /// assert_eq!(&*value, &mut [1u32, 2u32][..]); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn map(this: Self, m: M) -> BorrowMut<'a, U> where @@ -547,7 +547,7 @@ impl<'a, T: ?Sized> BorrowMut<'a, T> { /// let mut value: Option> = BorrowMut::try_map(vec, |vec| vec.get_mut(0..2)); /// /// assert_eq!(value.as_deref_mut(), Some(&mut [1u32, 2u32][..])); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn try_map(this: Self, m: M) -> Option> where diff --git a/crates/rune/src/runtime/budget.rs b/crates/rune/src/runtime/budget.rs index 6b3eaff6f..d3449b04a 100644 --- a/crates/rune/src/runtime/budget.rs +++ b/crates/rune/src/runtime/budget.rs @@ -17,7 +17,7 @@ use pin_project::pin_project; #[cfg(feature = "std")] #[cfg(not(feature = "std"))] -static BUDGET: Cell = Cell::new(usize::max_value()); +static BUDGET: Cell = Cell::new(usize::MAX); /// Something being budgeted. #[pin_project] diff --git a/crates/rune/src/runtime/budget/std.rs b/crates/rune/src/runtime/budget/std.rs index 2ec13186c..c0f723165 100644 --- a/crates/rune/src/runtime/budget/std.rs +++ b/crates/rune/src/runtime/budget/std.rs @@ -1,12 +1,12 @@ use core::cell::Cell; -std::thread_local!(static BUDGET: Cell = Cell::new(usize::max_value())); +std::thread_local!(static BUDGET: Cell = Cell::new(usize::MAX)); pub(super) fn rune_budget_take() -> bool { BUDGET.with(|tls| { let v = tls.get(); - if v == usize::max_value() { + if v == usize::MAX { true } else if v == 0 { false diff --git a/crates/rune/src/runtime/bytes.rs b/crates/rune/src/runtime/bytes.rs index a0e1c8e45..f1a693557 100644 --- a/crates/rune/src/runtime/bytes.rs +++ b/crates/rune/src/runtime/bytes.rs @@ -6,20 +6,19 @@ use core::cmp; use core::fmt; use core::ops; -use crate::no_std::prelude::*; - -use serde::{Deserialize, Serialize}; +use serde::de; +use serde::ser; use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, Vec}; use crate::runtime::{RawRef, Ref, UnsafeToRef, Value, VmResult}; use crate::Any; /// A vector of bytes. -#[derive(Any, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] -#[serde(transparent)] +#[derive(Any, PartialEq, Eq, PartialOrd, Ord, Hash)] #[rune(builtin, static_type = BYTES_TYPE)] pub struct Bytes { - #[serde(with = "serde_bytes")] pub(crate) bytes: Vec, } @@ -46,16 +45,17 @@ impl Bytes { /// ``` /// use rune::runtime::Bytes; /// - /// let mut bytes = Bytes::with_capacity(32); + /// let mut bytes = Bytes::with_capacity(32)?; /// assert_eq!(bytes, b""); - /// bytes.extend(b"abcd"); + /// bytes.extend(b"abcd")?; /// assert_eq!(bytes, b"abcd"); + /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] - pub fn with_capacity(cap: usize) -> Self { - Bytes { - bytes: Vec::with_capacity(cap), - } + pub fn with_capacity(cap: usize) -> alloc::Result { + Ok(Self { + bytes: Vec::try_with_capacity(cap)?, + }) } /// Convert the byte array into a vector of bytes. @@ -64,9 +64,13 @@ impl Bytes { /// /// ``` /// use rune::runtime::Bytes; + /// use rune::alloc::prelude::*; + /// use rune::alloc::try_vec; /// - /// let bytes = Bytes::from_vec(vec![b'a', b'b', b'c', b'd']); + /// let bytes = Bytes::from_vec(try_vec![b'a', b'b', b'c', b'd']); /// assert_eq!(bytes.into_vec(), [b'a', b'b', b'c', b'd']); + /// + /// Ok::<_, rune::support::Error>(()) /// ``` #[inline] pub fn into_vec(self) -> Vec { @@ -79,9 +83,12 @@ impl Bytes { /// /// ``` /// use rune::runtime::Bytes; + /// use rune::alloc::try_vec; /// - /// let bytes = Bytes::from_vec(vec![b'a', b'b', b'c', b'd']); + /// let bytes = Bytes::from_vec(try_vec![b'a', b'b', b'c', b'd']); /// assert_eq!(bytes.as_slice(), &[b'a', b'b', b'c', b'd']); + /// + /// Ok::<_, rune::support::Error>(()) /// ``` #[inline] pub fn as_slice(&self) -> &[u8] { @@ -97,17 +104,19 @@ impl Bytes { /// ``` /// use rune::runtime::Bytes; /// - /// let bytes = Bytes::from_slice(vec![b'a', b'b', b'c', b'd']); + /// let bytes = Bytes::from_slice(vec![b'a', b'b', b'c', b'd'])?; /// assert_eq!(bytes, b"abcd"); + /// + /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] - pub fn from_slice(bytes: B) -> Self + pub fn from_slice(bytes: B) -> alloc::Result where B: AsRef<[u8]>, { - Self { - bytes: bytes.as_ref().to_vec(), - } + Ok(Self { + bytes: Vec::try_from(bytes.as_ref())?, + }) } /// Convert a byte array into bytes. @@ -116,9 +125,11 @@ impl Bytes { /// /// ``` /// use rune::runtime::Bytes; + /// use rune::alloc::try_vec; /// - /// let bytes = Bytes::from_vec(vec![b'a', b'b', b'c', b'd']); + /// let bytes = Bytes::from_vec(try_vec![b'a', b'b', b'c', b'd']); /// assert_eq!(bytes, b"abcd"); + /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] pub fn from_vec(bytes: Vec) -> Self { @@ -131,16 +142,19 @@ impl Bytes { /// /// ``` /// use rune::runtime::Bytes; + /// use rune::alloc::try_vec; /// - /// let mut bytes = Bytes::from_vec(vec![b'a', b'b', b'c', b'd']); + /// let mut bytes = Bytes::from_vec(try_vec![b'a', b'b', b'c', b'd']); /// bytes.extend(b"efgh"); /// assert_eq!(bytes, b"abcdefgh"); + /// + /// Ok::<_, rune::support::Error>(()) /// ``` - pub fn extend(&mut self, other: O) + pub fn extend(&mut self, other: O) -> alloc::Result<()> where O: AsRef<[u8]>, { - self.bytes.extend_from_slice(other.as_ref()); + self.bytes.try_extend_from_slice(other.as_ref()) } /// Test if the collection is empty. @@ -186,18 +200,18 @@ impl Bytes { /// Reserve additional space. /// /// The exact amount is unspecified. - pub fn reserve(&mut self, additional: usize) { - self.bytes.reserve(additional); + pub fn reserve(&mut self, additional: usize) -> alloc::Result<()> { + self.bytes.try_reserve(additional) } /// Resever additional space to the exact amount specified. - pub fn reserve_exact(&mut self, additional: usize) { - self.bytes.reserve_exact(additional); + pub fn reserve_exact(&mut self, additional: usize) -> alloc::Result<()> { + self.bytes.try_reserve_exact(additional) } /// Shrink to fit the amount of bytes in the container. - pub fn shrink_to_fit(&mut self) { - self.bytes.shrink_to_fit(); + pub fn shrink_to_fit(&mut self) -> alloc::Result<()> { + self.bytes.try_shrink_to_fit() } /// Pop the last byte. @@ -207,9 +221,10 @@ impl Bytes { /// ``` /// use rune::runtime::Bytes; /// - /// let mut bytes = Bytes::from_slice(b"abcd"); + /// let mut bytes = Bytes::from_slice(b"abcd")?; /// assert_eq!(bytes.pop(), Some(b'd')); /// assert_eq!(bytes, b"abc"); + /// Ok::<_, rune::support::Error>(()) /// ``` pub fn pop(&mut self) -> Option { self.bytes.pop() @@ -222,8 +237,10 @@ impl Bytes { /// ``` /// use rune::runtime::Bytes; /// - /// let bytes = Bytes::from_slice(b"abcd"); + /// let bytes = Bytes::from_slice(b"abcd")?; /// assert_eq!(bytes.first(), Some(b'a')); + /// + /// Ok::<_, rune::support::Error>(()) /// ``` pub fn first(&self) -> Option { self.bytes.first().copied() @@ -236,14 +253,24 @@ impl Bytes { /// ``` /// use rune::runtime::Bytes; /// - /// let bytes = Bytes::from_slice(b"abcd"); + /// let bytes = Bytes::from_slice(b"abcd")?; /// assert_eq!(bytes.last(), Some(b'd')); + /// + /// Ok::<_, rune::support::Error>(()) /// ``` pub fn last(&self) -> Option { self.bytes.last().copied() } } +impl TryClone for Bytes { + fn try_clone(&self) -> alloc::Result { + Ok(Self { + bytes: self.bytes.try_clone()?, + }) + } +} + impl From> for Bytes { #[inline] fn from(bytes: Vec) -> Self { @@ -251,15 +278,39 @@ impl From> for Bytes { } } +#[cfg(feature = "alloc")] +impl TryFrom<::rust_alloc::vec::Vec> for Bytes { + type Error = alloc::Error; + + #[inline] + fn try_from(bytes: ::rust_alloc::vec::Vec) -> Result { + Ok(Self { + bytes: Vec::try_from(bytes)?, + }) + } +} + impl From> for Bytes { #[inline] fn from(bytes: Box<[u8]>) -> Self { Self { - bytes: bytes.into(), + bytes: Vec::from(bytes), } } } +#[cfg(feature = "alloc")] +impl TryFrom<::rust_alloc::boxed::Box<[u8]>> for Bytes { + type Error = alloc::Error; + + #[inline] + fn try_from(bytes: ::rust_alloc::boxed::Box<[u8]>) -> Result { + Ok(Self { + bytes: Vec::try_from(bytes.as_ref())?, + }) + } +} + impl fmt::Debug for Bytes { #[inline] fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -347,8 +398,46 @@ impl cmp::PartialEq for [u8] { } } +impl ser::Serialize for Bytes { + fn serialize(&self, serializer: S) -> Result + where + S: ser::Serializer, + { + serializer.serialize_bytes(&self.bytes) + } +} + +impl<'de> de::Deserialize<'de> for Bytes { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = Bytes; + + #[inline] + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "a byte array") + } + + #[inline] + fn visit_bytes(self, v: &[u8]) -> Result + where + E: de::Error, + { + Bytes::from_slice(v).map_err(E::custom) + } + } + + deserializer.deserialize_bytes(Visitor) + } +} + #[cfg(test)] mod tests { + use crate::alloc::clone::TryClone; use crate::no_std::prelude::*; use crate::runtime::{Bytes, Shared, Value}; @@ -359,7 +448,7 @@ mod tests { let _ = { let shared = shared.into_bytes().into_result()?; - let out = shared.borrow_ref()?.clone(); + let out = shared.borrow_ref()?.try_clone()?; out }; diff --git a/crates/rune/src/runtime/call.rs b/crates/rune/src/runtime/call.rs index 211ae7373..db80ea4df 100644 --- a/crates/rune/src/runtime/call.rs +++ b/crates/rune/src/runtime/call.rs @@ -3,10 +3,13 @@ use core::fmt; use musli::{Decode, Encode}; use serde::{Deserialize, Serialize}; +use crate as rune; +use crate::alloc::prelude::*; use crate::runtime::{Future, Generator, Stream, Value, Vm, VmResult}; /// The calling convention of a function. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Encode, Decode)] +#[try_clone(copy)] #[non_exhaustive] pub enum Call { /// Function is `async` and returns a future that must be await:ed to make diff --git a/crates/rune/src/runtime/const_value.rs b/crates/rune/src/runtime/const_value.rs index 2eadcfb5c..81037fe71 100644 --- a/crates/rune/src/runtime/const_value.rs +++ b/crates/rune/src/runtime/const_value.rs @@ -1,16 +1,14 @@ use serde::{Deserialize, Serialize}; -use crate::no_std::collections::HashMap; -use crate::no_std::std; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, HashMap, String, Vec}; use crate::runtime::{ - Bytes, FromValue, Object, OwnedTuple, Shared, ToValue, TypeInfo, Value, Vec, VmErrorKind, + self, Bytes, FromValue, Object, OwnedTuple, Shared, ToValue, TypeInfo, Value, VmErrorKind, VmResult, }; -use crate::alloc::{Error, TryClone}; - /// A constant value. -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize)] pub enum ConstValue { /// A constant unit. EmptyTuple, @@ -25,17 +23,17 @@ pub enum ConstValue { /// An float constant. Float(f64), /// A string constant designated by its slot. - String(std::String), + String(String), /// A byte string. Bytes(Bytes), /// A vector of values. - Vec(std::Vec), + Vec(Vec), /// An anonymous tuple. - Tuple(std::Box<[ConstValue]>), + Tuple(Box<[ConstValue]>), /// An anonymous object. - Object(HashMap), + Object(HashMap), /// An option. - Option(Option>), + Option(Option>), } impl ConstValue { @@ -44,24 +42,21 @@ impl ConstValue { /// We provide this associated method since a constant value can be /// converted into a value infallibly, which is not captured by the trait /// otherwise. - pub fn into_value(self) -> Result { + pub fn into_value(self) -> alloc::Result { Ok(match self { Self::Byte(b) => Value::Byte(b), Self::Char(c) => Value::Char(c), Self::Bool(b) => Value::Bool(b), Self::Integer(n) => Value::Integer(n), Self::Float(n) => Value::Float(n), - Self::String(string) => { - let string = rune_alloc::String::try_from(string)?; - Value::String(Shared::new(string)?) - } + Self::String(string) => Value::String(Shared::new(string)?), Self::Bytes(b) => Value::Bytes(Shared::new(b)?), Self::Option(option) => Value::Option(Shared::new(match option { - Some(some) => Some(some.into_value()?), + Some(some) => Some(Box::into_inner(some).into_value()?), None => None, })?), Self::Vec(vec) => { - let mut v = Vec::with_capacity(vec.len())?; + let mut v = runtime::Vec::with_capacity(vec.len())?; for value in vec { v.push(value.into_value()?)?; @@ -71,11 +66,10 @@ impl ConstValue { } Self::EmptyTuple => Value::EmptyTuple, Self::Tuple(tuple) => { - let mut t = rune_alloc::Vec::try_with_capacity(tuple.len())?; + let mut t = Vec::try_with_capacity(tuple.len())?; - for value in std::Vec::from(tuple) { - let value = value.into_value()?; - t.try_push(value)?; + for value in Vec::from(tuple) { + t.try_push(value.into_value()?)?; } Value::Tuple(Shared::new(OwnedTuple::try_from(t)?)?) @@ -84,7 +78,6 @@ impl ConstValue { let mut o = Object::with_capacity(object.len())?; for (key, value) in object { - let key = rune_alloc::String::try_from(key)?; o.insert(key, value.into_value()?)?; } @@ -120,6 +113,25 @@ impl ConstValue { } } +impl TryClone for ConstValue { + fn try_clone(&self) -> alloc::Result { + Ok(match self { + ConstValue::EmptyTuple => ConstValue::EmptyTuple, + ConstValue::Byte(byte) => ConstValue::Byte(*byte), + ConstValue::Char(char) => ConstValue::Char(*char), + ConstValue::Bool(bool) => ConstValue::Bool(*bool), + ConstValue::Integer(integer) => ConstValue::Integer(*integer), + ConstValue::Float(float) => ConstValue::Float(*float), + ConstValue::String(value) => ConstValue::String(value.try_clone()?), + ConstValue::Bytes(value) => ConstValue::Bytes(value.try_clone()?), + ConstValue::Vec(value) => ConstValue::Vec(value.try_clone()?), + ConstValue::Tuple(value) => ConstValue::Tuple(value.try_clone()?), + ConstValue::Object(value) => ConstValue::Object(value.try_clone()?), + ConstValue::Option(value) => ConstValue::Option(value.try_clone()?), + }) + } +} + impl FromValue for ConstValue { fn from_value(value: Value) -> VmResult { VmResult::Ok(match value { @@ -129,12 +141,9 @@ impl FromValue for ConstValue { Value::Bool(b) => Self::Bool(b), Value::Integer(n) => Self::Integer(n), Value::Float(f) => Self::Float(f), - Value::String(s) => { - let s = vm_try!(s.take()); - Self::String(std::String::from(s)) - } + Value::String(s) => Self::String(vm_try!(s.take())), Value::Option(option) => Self::Option(match vm_try!(option.take()) { - Some(some) => Some(std::Box::new(vm_try!(Self::from_value(some)))), + Some(some) => Some(vm_try!(Box::try_new(vm_try!(Self::from_value(some))))), None => None, }), Value::Bytes(b) => { @@ -143,31 +152,30 @@ impl FromValue for ConstValue { } Value::Vec(vec) => { let vec = vm_try!(vec.take()); - let mut const_vec = std::Vec::with_capacity(vec.len()); + let mut const_vec = vm_try!(Vec::try_with_capacity(vec.len())); for value in vec { - const_vec.push(vm_try!(Self::from_value(value))); + vm_try!(const_vec.try_push(vm_try!(Self::from_value(value)))); } Self::Vec(const_vec) } Value::Tuple(tuple) => { let tuple = vm_try!(tuple.take()); - let mut const_tuple = std::Vec::with_capacity(tuple.len()); + let mut const_tuple = vm_try!(Vec::try_with_capacity(tuple.len())); - for value in rune_alloc::Vec::from(tuple.into_inner()) { - const_tuple.push(vm_try!(Self::from_value(value))); + for value in Vec::from(tuple.into_inner()) { + vm_try!(const_tuple.try_push(vm_try!(Self::from_value(value)))); } - Self::Tuple(const_tuple.into_boxed_slice()) + Self::Tuple(vm_try!(const_tuple.try_into_boxed_slice())) } Value::Object(object) => { let object = vm_try!(object.take()); - let mut const_object = HashMap::with_capacity(object.len()); + let mut const_object = vm_try!(HashMap::try_with_capacity(object.len())); for (key, value) in object { - let key = std::String::from(key); - const_object.insert(key, vm_try!(Self::from_value(value))); + vm_try!(const_object.try_insert(key, vm_try!(Self::from_value(value)))); } Self::Object(const_object) @@ -181,13 +189,6 @@ impl FromValue for ConstValue { } } -impl TryClone for ConstValue { - fn try_clone(&self) -> Result { - // TODO: perform fallible allocations. - Ok(self.clone()) - } -} - impl ToValue for ConstValue { fn to_value(self) -> VmResult { VmResult::Ok(vm_try!(ConstValue::into_value(self))) diff --git a/crates/rune/src/runtime/debug.rs b/crates/rune/src/runtime/debug.rs index 2264bc3eb..9b4ced5cf 100644 --- a/crates/rune/src/runtime/debug.rs +++ b/crates/rune/src/runtime/debug.rs @@ -2,11 +2,11 @@ use core::fmt; -use crate::no_std::collections::HashMap; -use crate::no_std::prelude::*; - use serde::{Deserialize, Serialize}; +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{Box, HashMap, Vec}; use crate::ast::Span; use crate::compile::ItemBuf; use crate::hash::Hash; @@ -14,7 +14,7 @@ use crate::runtime::DebugLabel; use crate::SourceId; /// Debug information about a unit. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Debug, TryClone, Default, Serialize, Deserialize)] #[non_exhaustive] pub struct DebugInfo { /// Debug information on each instruction. @@ -47,7 +47,7 @@ impl DebugInfo { } /// Debug information for every instruction. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, TryClone, Serialize, Deserialize)] #[non_exhaustive] pub struct DebugInst { /// The file by id the instruction belongs to. @@ -78,7 +78,7 @@ impl DebugInst { } /// Debug information on function arguments. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, TryClone, Serialize, Deserialize)] pub enum DebugArgs { /// An empty, with not arguments. EmptyArgs, @@ -89,7 +89,7 @@ pub enum DebugArgs { } /// A description of a function signature. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, TryClone, Serialize, Deserialize)] #[non_exhaustive] pub struct DebugSignature { /// The path of the function. diff --git a/crates/rune/src/runtime/fmt.rs b/crates/rune/src/runtime/fmt.rs index 37de8968d..24a570c25 100644 --- a/crates/rune/src/runtime/fmt.rs +++ b/crates/rune/src/runtime/fmt.rs @@ -1,7 +1,7 @@ use crate as rune; use crate::alloc::fmt::TryWrite; -use crate::alloc::{Error, Global, String}; +use crate::alloc::{Error, String}; use crate::Any; /// A formatter for the rune virtual machine. @@ -14,8 +14,8 @@ use crate::Any; #[derive(Any)] #[rune(item = ::std::fmt)] pub struct Formatter { - pub(crate) string: String, - pub(crate) buf: String, + pub(crate) string: String, + pub(crate) buf: String, } impl Formatter { @@ -31,26 +31,26 @@ impl Formatter { #[inline] pub fn new() -> Self { Self { - string: String::new_in(Global), - buf: String::new_in(Global), + string: String::new(), + buf: String::new(), } } #[inline] pub(crate) fn with_capacity(capacity: usize) -> Result { Ok(Self { - string: String::try_with_capacity_in(capacity, Global)?, - buf: String::new_in(Global), + string: String::try_with_capacity(capacity)?, + buf: String::new(), }) } #[inline] - pub(crate) fn parts_mut(&mut self) -> (&mut String, &str) { + pub(crate) fn parts_mut(&mut self) -> (&mut String, &str) { (&mut self.string, &self.buf) } #[inline] - pub(crate) fn buf_mut(&mut self) -> &mut String { + pub(crate) fn buf_mut(&mut self) -> &mut String { &mut self.buf } @@ -65,7 +65,7 @@ impl Formatter { } #[inline] - pub(crate) fn into_string(self) -> String { + pub(crate) fn into_string(self) -> String { self.string } diff --git a/crates/rune/src/runtime/format.rs b/crates/rune/src/runtime/format.rs index bc73ae6c3..157eb3954 100644 --- a/crates/rune/src/runtime/format.rs +++ b/crates/rune/src/runtime/format.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use crate as rune; use crate::alloc::fmt::TryWrite; -use crate::alloc::{Global, String}; +use crate::alloc::String; use crate::runtime::{Formatter, ProtocolCaller, Value, VmErrorKind, VmResult}; use crate::Any; @@ -119,14 +119,14 @@ impl FormatSpec { } /// Format the given number. - fn format_number(&self, buf: &mut String, n: i64) -> VmResult<()> { + fn format_number(&self, buf: &mut String, n: i64) -> VmResult<()> { let mut buffer = itoa::Buffer::new(); vm_try!(buf.try_push_str(buffer.format(n))); VmResult::Ok(()) } /// Format the given float. - fn format_float(&self, buf: &mut String, n: f64) -> VmResult<()> { + fn format_float(&self, buf: &mut String, n: f64) -> VmResult<()> { if let Some(precision) = self.precision { vm_write!(buf, "{:.*}", precision.get(), n); } else { diff --git a/crates/rune/src/runtime/from_value.rs b/crates/rune/src/runtime/from_value.rs index cf31ed425..507127f9a 100644 --- a/crates/rune/src/runtime/from_value.rs +++ b/crates/rune/src/runtime/from_value.rs @@ -36,7 +36,7 @@ use crate::Any; /// let foo: Foo = rune::from_value(foo)?; /// /// assert_eq!(foo.field, 42); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` pub use rune_macros::FromValue; @@ -68,7 +68,7 @@ pub use rune_macros::FromValue; /// let foo: u64 = rune::from_value(foo)?; /// /// assert_eq!(foo, 43); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` pub fn from_value(value: Value) -> Result where @@ -101,7 +101,7 @@ where /// let foo: Foo = rune::from_value(foo)?; /// /// assert_eq!(foo.field, 42); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` pub trait FromValue: 'static + Sized { /// Try to convert to the given type, from the given value. diff --git a/crates/rune/src/runtime/function.rs b/crates/rune/src/runtime/function.rs index a03233516..30b5e0c36 100644 --- a/crates/rune/src/runtime/function.rs +++ b/crates/rune/src/runtime/function.rs @@ -4,7 +4,8 @@ use core::future::Future; use crate::no_std::sync::Arc; use crate as rune; -use crate::alloc::{Box, Error, TryClone, Vec}; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, Vec}; use crate::module; use crate::runtime::{ Args, Call, ConstValue, FromValue, FunctionHandler, OwnedTuple, Rtti, RuntimeContext, Stack, @@ -72,7 +73,7 @@ impl Function { /// let value = vm.call(["main"], (function,))?; /// let value: u32 = rune::from_value(value)?; /// assert_eq!(value, 42); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` /// /// Asynchronous functions: @@ -101,9 +102,9 @@ impl Function { /// let value = vm.async_call(["main"], (function,)).await?; /// let value: u32 = rune::from_value(value)?; /// assert_eq!(value, 42); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// # })?; - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn new(f: F) -> Self where @@ -172,7 +173,7 @@ impl Function { /// /// let value: Function = rune::from_value(value)?; /// assert_eq!(value.call::<_, u32>((1, 2)).into_result()?, 3); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn call(&self, args: A) -> VmResult where @@ -278,7 +279,7 @@ impl Function { /// let pony: Function = rune::from_value(pony)?; /// /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"])); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn type_hash(&self) -> Hash { self.0.type_hash() @@ -312,7 +313,7 @@ impl Function { /// let pony = pony.into_sync().into_result()?; /// /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"])); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` /// /// The following *does not* work, because we return a closure which tries @@ -348,7 +349,7 @@ impl Function { /// // This is *not* fine since the returned closure has captured a /// // generator which is not a constant value. /// assert!(closure.into_sync().is_err()); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn into_sync(self) -> VmResult { VmResult::Ok(SyncFunction(vm_try!(self.0.into_sync()))) @@ -389,9 +390,9 @@ impl SyncFunction { /// /// let value = add.async_send_call::<_, u32>((1, 2)).await.into_result()?; /// assert_eq!(value, 3); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// # })?; - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub async fn async_send_call(&self, args: A) -> VmResult where @@ -426,7 +427,7 @@ impl SyncFunction { /// let add: SyncFunction = rune::from_value(add)?; /// /// assert_eq!(add.call::<_, u32>((1, 2)).into_result()?, 3); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn call(&self, args: A) -> VmResult where @@ -462,7 +463,7 @@ impl SyncFunction { /// let pony: SyncFunction = rune::from_value(pony)?; /// /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"])); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn type_hash(&self) -> Hash { self.0.type_hash() @@ -470,7 +471,7 @@ impl SyncFunction { } impl TryClone for SyncFunction { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self(self.0.try_clone()?)) } } @@ -485,7 +486,7 @@ where V: TryClone, { #[inline] - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { inner: self.inner.try_clone()?, }) @@ -829,7 +830,7 @@ impl TryClone for Inner where V: TryClone, { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(match self { Inner::FnHandler(inner) => Inner::FnHandler(inner.clone()), Inner::FnOffset(inner) => Inner::FnOffset(inner.clone()), @@ -948,7 +949,7 @@ where V: TryClone, { #[inline] - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { fn_offset: self.fn_offset.clone(), environment: self.environment.try_clone()?, diff --git a/crates/rune/src/runtime/generator_state.rs b/crates/rune/src/runtime/generator_state.rs index ccaf28cb7..28857d46a 100644 --- a/crates/rune/src/runtime/generator_state.rs +++ b/crates/rune/src/runtime/generator_state.rs @@ -46,7 +46,7 @@ use crate::Any; /// }; /// /// assert_eq!(ret, 42); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any, Debug)] #[rune(builtin, static_type = GENERATOR_STATE_TYPE)] diff --git a/crates/rune/src/runtime/inst.rs b/crates/rune/src/runtime/inst.rs index 1aad1c857..6d7f4187b 100644 --- a/crates/rune/src/runtime/inst.rs +++ b/crates/rune/src/runtime/inst.rs @@ -4,6 +4,8 @@ use musli::{Decode, Encode}; use rune_macros::InstDisplay; use serde::{Deserialize, Serialize}; +use crate as rune; +use crate::alloc::prelude::*; use crate::runtime::{Call, FormatSpec, Type, Value}; use crate::Hash; @@ -11,7 +13,8 @@ use crate::Hash; /// /// To formulate a custom reason, use /// [`VmError::panic`][crate::runtime::VmError::panic]. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] #[non_exhaustive] pub enum PanicReason { /// Not implemented. @@ -48,7 +51,8 @@ impl fmt::Display for PanicReason { } /// Type checks for built-in types. -#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] #[non_exhaustive] pub enum TypeCheck { /// Matches a unit type. @@ -88,7 +92,8 @@ impl fmt::Display for TypeCheck { } /// An operation in the stack-based virtual machine. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode, InstDisplay)] +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode, InstDisplay)] +#[try_clone(copy)] pub enum Inst { /// Not operator. Takes a boolean from the top of the stack and inverts its /// logical value. @@ -1125,7 +1130,8 @@ impl Inst { } /// How an instruction addresses a value. -#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Default, Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] pub enum InstAddress { /// Addressed from the top of the stack. #[default] @@ -1145,7 +1151,8 @@ impl fmt::Display for InstAddress { } /// Range limits of a range expression. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] pub enum InstRange { /// `start..`. RangeFrom, @@ -1175,7 +1182,8 @@ impl fmt::Display for InstRange { } /// The target of an operation. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Encode, Decode)] +#[try_clone(copy)] pub enum InstTarget { /// Target is an offset to the current call frame. #[musli(packed)] @@ -1199,7 +1207,8 @@ impl fmt::Display for InstTarget { } /// An operation between two values on the machine. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] pub enum InstAssignOp { /// The add operation. `a + b`. Add, @@ -1263,7 +1272,8 @@ impl fmt::Display for InstAssignOp { } /// An operation between two values on the machine. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] pub enum InstOp { /// The add operation. `a + b`. Add, @@ -1447,7 +1457,8 @@ impl fmt::Display for InstOp { } /// A literal value that can be pushed. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] #[non_exhaustive] pub enum InstValue { /// An empty tuple. @@ -1510,7 +1521,8 @@ impl fmt::Display for InstValue { } /// A variant that can be constructed. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[derive(Debug, TryClone, Clone, Copy, Serialize, Deserialize, Decode, Encode)] +#[try_clone(copy)] pub enum InstVariant { /// `Option::Some`, which uses one value. Some, diff --git a/crates/rune/src/runtime/iterator.rs b/crates/rune/src/runtime/iterator.rs index bb7c81f23..b726064dd 100644 --- a/crates/rune/src/runtime/iterator.rs +++ b/crates/rune/src/runtime/iterator.rs @@ -5,7 +5,7 @@ use core::iter; use crate::no_std::prelude::*; use crate as rune; -use crate::alloc::{self, Global}; +use crate::alloc; use crate::runtime::{FromValue, Function, Panic, ToValue, Value, VmErrorKind, VmResult}; use crate::Any; @@ -292,7 +292,7 @@ impl Iterator { T: FromValue, { let (cap, _) = self.iter.size_hint(); - let mut vec = vm_try!(alloc::Vec::try_with_capacity_in(cap, Global)); + let mut vec = vm_try!(alloc::Vec::try_with_capacity(cap)); while let Some(value) = vm_try!(self.next()) { vm_try!(vec.try_push(vm_try!(T::from_value(value)))); diff --git a/crates/rune/src/runtime/label.rs b/crates/rune/src/runtime/label.rs index f0cd6e3c8..19172985a 100644 --- a/crates/rune/src/runtime/label.rs +++ b/crates/rune/src/runtime/label.rs @@ -4,16 +4,19 @@ use core::cell::Cell; use core::fmt; use core::num::NonZeroUsize; -use crate::no_std::borrow::Cow; +use crate as rune; +use crate::alloc::borrow::Cow; +use crate::alloc::prelude::*; use crate::no_std::rc::Rc; use serde::{Deserialize, Serialize}; /// A label that can be jumped to. -#[derive(Debug, Clone)] +#[derive(Debug, TryClone)] pub(crate) struct Label { pub(crate) name: &'static str, pub(crate) index: usize, + #[try_clone(with = Rc::clone)] jump: Rc>>, } @@ -63,7 +66,7 @@ impl fmt::Display for Label { } /// A label that can be jumped to. -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Debug, TryClone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct DebugLabel { /// The name of the label. name: Cow<'static, str>, diff --git a/crates/rune/src/runtime/object.rs b/crates/rune/src/runtime/object.rs index 32949d6a7..0d0390081 100644 --- a/crates/rune/src/runtime/object.rs +++ b/crates/rune/src/runtime/object.rs @@ -5,8 +5,9 @@ use core::fmt; use core::hash; use core::iter; +use crate::alloc::prelude::*; +use crate::alloc::{self, String}; use crate::alloc::{btree_map, BTreeMap}; -use crate::alloc::{Error, Global, String, TryClone}; use crate as rune; use crate::compile::ItemBuf; @@ -75,13 +76,13 @@ pub type Values<'a> = btree_map::Values<'a, String, Value>; /// assert_eq!(Some(42), object.get_value("foo").into_result()?); /// assert_eq!(Some(true), object.get_value("bar").into_result()?); /// assert_eq!(None::, object.get_value("baz").into_result()?); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any, Default)] #[repr(transparent)] #[rune(builtin, static_type = OBJECT_TYPE)] pub struct Object { - inner: BTreeMap, + inner: BTreeMap, } impl Object { @@ -97,7 +98,7 @@ impl Object { #[rune::function(keep, path = Self::new)] pub fn new() -> Self { Self { - inner: BTreeMap::new_in(Global), + inner: BTreeMap::new(), } } @@ -116,11 +117,11 @@ impl Object { } /// Construct a new object with the given capacity. - pub fn with_capacity(#[allow(unused)] capacity: usize) -> Result { + pub fn with_capacity(#[allow(unused)] capacity: usize) -> alloc::Result { // BTreeMap doesn't support setting capacity on creation but we keep // this here in case we want to switch store later. Ok(Self { - inner: BTreeMap::new_in(Global), + inner: BTreeMap::new(), }) } @@ -246,7 +247,7 @@ impl Object { /// Inserts a key-value pair into the map. /// /// If the map did not have this key present, `None` is returned. - pub fn insert(&mut self, k: String, v: Value) -> Result, Error> { + pub fn insert(&mut self, k: String, v: Value) -> alloc::Result> { Ok(self.inner.try_insert(k, v)?) } @@ -462,7 +463,7 @@ impl Object { } impl TryClone for Object { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { inner: self.inner.try_clone()?, }) diff --git a/crates/rune/src/runtime/protocol.rs b/crates/rune/src/runtime/protocol.rs index 46590f8f3..858e585df 100644 --- a/crates/rune/src/runtime/protocol.rs +++ b/crates/rune/src/runtime/protocol.rs @@ -1,3 +1,6 @@ +use crate::alloc; +#[cfg(feature = "doc")] +use crate::alloc::Vec; use crate::compile::meta; use crate::module::{AssociatedFunctionName, ToInstance}; use crate::Hash; @@ -7,12 +10,12 @@ pub use rune_core::Protocol; impl ToInstance for Protocol { #[inline] - fn to_instance(self) -> AssociatedFunctionName { - AssociatedFunctionName { + fn to_instance(self) -> alloc::Result { + Ok(AssociatedFunctionName { associated: meta::AssociatedKind::Protocol(self), function_parameters: Hash::EMPTY, #[cfg(feature = "doc")] - parameter_types: vec![], - } + parameter_types: Vec::new(), + }) } } diff --git a/crates/rune/src/runtime/range.rs b/crates/rune/src/runtime/range.rs index d718a2807..95d37d35a 100644 --- a/crates/rune/src/runtime/range.rs +++ b/crates/rune/src/runtime/range.rs @@ -49,7 +49,7 @@ use crate::Any; /// let start = rune::to_value(1)?; /// let end = rune::to_value(10)?; /// let _ = Range::new(start, end); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any, Clone)] #[rune(builtin, constructor, from_value = Value::into_range, static_type = RANGE_TYPE)] diff --git a/crates/rune/src/runtime/range_from.rs b/crates/rune/src/runtime/range_from.rs index 34e6ecc16..d7b0609a3 100644 --- a/crates/rune/src/runtime/range_from.rs +++ b/crates/rune/src/runtime/range_from.rs @@ -46,7 +46,7 @@ use crate::Any; /// /// let start = rune::to_value(1)?; /// let _ = RangeFrom::new(start); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any, Clone)] #[rune(builtin, constructor, from_value = Value::into_range_from, static_type = RANGE_FROM_TYPE)] diff --git a/crates/rune/src/runtime/range_full.rs b/crates/rune/src/runtime/range_full.rs index 3ef2025ec..32d608942 100644 --- a/crates/rune/src/runtime/range_full.rs +++ b/crates/rune/src/runtime/range_full.rs @@ -27,7 +27,7 @@ use crate::Any; /// use rune::runtime::RangeFull; /// /// let _ = RangeFull::new(); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any, Default, Clone)] #[rune(builtin, constructor, from_value = Value::into_range_full, static_type = RANGE_FULL_TYPE)] diff --git a/crates/rune/src/runtime/range_inclusive.rs b/crates/rune/src/runtime/range_inclusive.rs index 751bfe1a6..7b477c7da 100644 --- a/crates/rune/src/runtime/range_inclusive.rs +++ b/crates/rune/src/runtime/range_inclusive.rs @@ -50,7 +50,7 @@ use crate::Any; /// let start = rune::to_value(1)?; /// let end = rune::to_value(10)?; /// let _ = RangeInclusive::new(start, end); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any, Clone)] #[rune(builtin, constructor, from_value = Value::into_range_inclusive, static_type = RANGE_INCLUSIVE_TYPE)] diff --git a/crates/rune/src/runtime/range_to.rs b/crates/rune/src/runtime/range_to.rs index 37a59c569..a8e1b158b 100644 --- a/crates/rune/src/runtime/range_to.rs +++ b/crates/rune/src/runtime/range_to.rs @@ -36,7 +36,7 @@ use crate::Any; /// /// let end = rune::to_value(1)?; /// let _ = RangeTo::new(end); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any, Clone)] #[rune(builtin, constructor, from_value = Value::into_range_to, static_type = RANGE_TO_TYPE)] diff --git a/crates/rune/src/runtime/range_to_inclusive.rs b/crates/rune/src/runtime/range_to_inclusive.rs index ae32393dd..305c14f13 100644 --- a/crates/rune/src/runtime/range_to_inclusive.rs +++ b/crates/rune/src/runtime/range_to_inclusive.rs @@ -36,7 +36,7 @@ use crate::Any; /// /// let end = rune::to_value(10)?; /// let _ = RangeToInclusive::new(end); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any, Clone)] #[rune(builtin, constructor, from_value = Value::into_range_to_inclusive, static_type = RANGE_TO_INCLUSIVE_TYPE)] diff --git a/crates/rune/src/runtime/runtime_context.rs b/crates/rune/src/runtime/runtime_context.rs index 50e61d3cd..96a143ead 100644 --- a/crates/rune/src/runtime/runtime_context.rs +++ b/crates/rune/src/runtime/runtime_context.rs @@ -2,6 +2,8 @@ use core::fmt; use crate::no_std::sync::Arc; +use crate as rune; +use crate::alloc::prelude::*; use crate::compile; use crate::hash; use crate::macros::{MacroContext, TokenStream}; @@ -26,7 +28,7 @@ pub(crate) type AttributeMacroHandler = dyn Fn(&mut MacroContext, &TokenStream, /// * Declared functions. /// * Declared instance functions. /// * Built-in type checks. -#[derive(Default, Clone)] +#[derive(Default, TryClone)] pub struct RuntimeContext { /// Registered native function handlers. functions: hash::Map>, diff --git a/crates/rune/src/runtime/shared.rs b/crates/rune/src/runtime/shared.rs index ea1e5e3bc..9eb095e64 100644 --- a/crates/rune/src/runtime/shared.rs +++ b/crates/rune/src/runtime/shared.rs @@ -13,7 +13,8 @@ use ::rust_alloc::rc::Rc; #[cfg(feature = "alloc")] use ::rust_alloc::sync::Arc; -use crate::alloc::{Box, Error, Global}; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box}; use crate::runtime::{ Access, AccessError, AccessKind, AnyObj, AnyObjError, BorrowMut, BorrowRef, RawAccessGuard, }; @@ -26,14 +27,14 @@ pub struct Shared { impl Shared { /// Construct a new shared value. - pub fn new(data: T) -> Result { + pub fn new(data: T) -> alloc::Result { let shared = SharedBox { access: Access::new(false), count: Cell::new(1), data: data.into(), }; - let inner = Box::leak(Box::try_new_in(shared, Global)?); + let inner = Box::leak(Box::try_new(shared)?); Ok(Self { inner: inner.into(), @@ -403,7 +404,7 @@ impl Shared { /// } /// # Ok::<_, rune::alloc::Error>(()) /// ``` - pub unsafe fn from_ref(data: &T) -> Result<(Self, SharedPointerGuard), Error> + pub unsafe fn from_ref(data: &T) -> alloc::Result<(Self, SharedPointerGuard)> where T: Any, { @@ -442,7 +443,7 @@ impl Shared { /// } /// # Ok::<_, rune::alloc::Error>(()) /// ``` - pub unsafe fn from_mut(data: &mut T) -> Result<(Self, SharedPointerGuard), Error> + pub unsafe fn from_mut(data: &mut T) -> alloc::Result<(Self, SharedPointerGuard)> where T: Any, { @@ -455,13 +456,13 @@ impl Shared { /// # Safety /// /// The reference must be valid for the duration of the guard. - unsafe fn unsafe_from_any_pointer(any: AnyObj) -> Result<(Self, SharedPointerGuard), Error> { + unsafe fn unsafe_from_any_pointer(any: AnyObj) -> alloc::Result<(Self, SharedPointerGuard)> { let shared = SharedBox { access: Access::new(true), count: Cell::new(2), data: any.into(), }; - let inner = ptr::NonNull::from(Box::leak(Box::try_new_in(shared, Global)?)); + let inner = ptr::NonNull::from(Box::leak(Box::try_new(shared)?)); let guard = SharedPointerGuard { _inner: RawDrop::take_shared_box(inner), @@ -499,7 +500,12 @@ impl Shared { let expected = TypeId::of::(); let (e, any) = match any.raw_take(expected) { - Ok(value) => return Ok(Box::into_inner(Box::from_raw_in(value as *mut T, Global))), + Ok(value) => { + return Ok(Box::into_inner(Box::from_raw_in( + value as *mut T, + rune_alloc::alloc::Global, + ))) + } Err((AnyObjError::Cast, any)) => { let actual = any.type_name(); @@ -690,6 +696,13 @@ impl Shared { } } +impl TryClone for Shared { + #[inline] + fn try_clone(&self) -> alloc::Result { + Ok(self.clone()) + } +} + impl Clone for Shared { fn clone(&self) -> Self { unsafe { @@ -776,8 +789,8 @@ impl SharedBox { unsafe fn inc(this: *const Self) { let count = (*this).count.get(); - if count == 0 || count == usize::max_value() { - crate::no_std::abort(); + if count == 0 || count == usize::MAX { + crate::alloc::abort(); } (*this).count.set(count + 1); @@ -793,7 +806,7 @@ impl SharedBox { let count = (*this).count.get(); if count == 0 { - crate::no_std::abort(); + crate::alloc::abort(); } let count = count - 1; @@ -803,7 +816,7 @@ impl SharedBox { return false; } - let this = Box::from_raw_in(this, Global); + let this = Box::from_raw_in(this, rune_alloc::alloc::Global); if this.access.is_taken() { // NB: This prevents the inner `T` from being dropped in case it @@ -1014,7 +1027,7 @@ impl Ref { /// let value: Ref<[u32]> = Ref::map(vec, |vec| &vec[0..2]); /// /// assert_eq!(&*value, &[1u32, 2u32][..]); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` #[inline] pub fn map(this: Self, f: F) -> Ref @@ -1049,7 +1062,7 @@ impl Ref { /// let value: Option> = Ref::try_map(vec, |vec| vec.get(0..2)); /// /// assert_eq!(value.as_deref(), Some(&[1u32, 2u32][..])); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn try_map(this: Self, f: F) -> Option> where @@ -1152,7 +1165,7 @@ impl Mut { /// let value: Mut<[u32]> = Mut::map(vec, |vec| &mut vec[0..2]); /// /// assert_eq!(&*value, &mut [1u32, 2u32][..]); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn map(this: Self, f: F) -> Mut where @@ -1189,7 +1202,7 @@ impl Mut { /// let mut value: Option> = Mut::try_map(vec, |vec| vec.get_mut(0..2)); /// /// assert_eq!(value.as_deref_mut(), Some(&mut [1u32, 2u32][..])); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn try_map(this: Self, f: F) -> Option> where diff --git a/crates/rune/src/runtime/stack.rs b/crates/rune/src/runtime/stack.rs index 7b3ada569..50f6f9531 100644 --- a/crates/rune/src/runtime/stack.rs +++ b/crates/rune/src/runtime/stack.rs @@ -5,7 +5,9 @@ use core::slice; use crate::no_std::borrow::Cow; -use crate::alloc::{Error, Global, IteratorExt, TryClone, TryFromIteratorIn, Vec}; +use crate::alloc::alloc::Global; +use crate::alloc::prelude::*; +use crate::alloc::{self, Vec}; use crate::runtime::{InstAddress, Value}; /// An error raised when interacting with the stack. @@ -44,7 +46,7 @@ impl Stack { /// assert!(stack.pop().is_err()); /// stack.push(rune::to_value(String::from("Hello World"))?); /// assert!(matches!(stack.pop()?, Value::String(..))); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub const fn new() -> Self { Self { @@ -63,9 +65,9 @@ impl Stack { /// assert!(stack.pop().is_err()); /// stack.push(rune::to_value(String::from("Hello World"))?); /// assert!(matches!(stack.pop()?, Value::String(..))); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn with_capacity(capacity: usize) -> Result { + pub fn with_capacity(capacity: usize) -> alloc::Result { Ok(Self { stack: Vec::try_with_capacity(capacity)?, stack_bottom: 0, @@ -84,7 +86,7 @@ impl Stack { /// assert!(stack.is_empty()); /// stack.push(rune::to_value(String::from("Hello World"))?); /// assert!(!stack.is_empty()); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` /// /// [stack_bottom]: Self::stack_bottom() @@ -104,7 +106,7 @@ impl Stack { /// assert_eq!(stack.len(), 0); /// stack.push(rune::to_value(String::from("Hello World"))?); /// assert_eq!(stack.len(), 1); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` /// /// [stack_bottom]: Self::stack_bottom() @@ -143,9 +145,9 @@ impl Stack { /// assert!(stack.pop().is_err()); /// stack.push(rune::to_value(String::from("Hello World"))?); /// assert!(matches!(stack.pop()?, Value::String(..))); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn push(&mut self, value: Value) -> Result<(), Error> { + pub fn push(&mut self, value: Value) -> alloc::Result<()> { self.stack.try_push(value)?; Ok(()) } @@ -160,7 +162,7 @@ impl Stack { /// assert!(stack.pop().is_err()); /// stack.push(rune::to_value(String::from("Hello World"))?); /// assert!(matches!(stack.pop()?, Value::String(..))); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn pop(&mut self) -> Result { if self.stack.len() == self.stack_bottom { @@ -188,7 +190,7 @@ impl Stack { /// assert!(matches!(it.next(), Some(Value::String(..)))); /// assert!(matches!(it.next(), Some(Value::EmptyTuple))); /// assert!(matches!(it.next(), None)); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn drain( &mut self, @@ -225,9 +227,9 @@ impl Stack { /// assert!(matches!(it.next(), Some(Value::String(..)))); /// assert!(matches!(it.next(), Some(Value::EmptyTuple))); /// assert!(matches!(it.next(), None)); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` - pub fn extend(&mut self, iter: I) -> Result<(), Error> + pub fn extend(&mut self, iter: I) -> alloc::Result<()> where I: IntoIterator, { @@ -334,7 +336,7 @@ impl Stack { pub(crate) fn pop_sequence( &mut self, count: usize, - ) -> Result, StackError>, Error> { + ) -> alloc::Result, StackError>> { let Ok(iter) = self.drain(count) else { return Ok(Err(StackError)); }; @@ -406,7 +408,7 @@ impl Stack { } impl TryClone for Stack { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { stack: self.stack.try_clone()?, stack_bottom: self.stack_bottom, @@ -415,9 +417,12 @@ impl TryClone for Stack { } impl TryFromIteratorIn for Stack { - fn try_from_iter_in>(iter: T, _: Global) -> Result { + fn try_from_iter_in>( + iter: T, + alloc: Global, + ) -> alloc::Result { Ok(Self { - stack: iter.into_iter().try_collect()?, + stack: iter.into_iter().try_collect_in(alloc)?, stack_bottom: 0, }) } diff --git a/crates/rune/src/runtime/static_string.rs b/crates/rune/src/runtime/static_string.rs index ead69fcf2..f3057fd04 100644 --- a/crates/rune/src/runtime/static_string.rs +++ b/crates/rune/src/runtime/static_string.rs @@ -3,14 +3,14 @@ use core::fmt; use core::hash; use core::ops; -use crate::no_std::prelude::*; - use serde::{Deserialize, Serialize}; +use crate::alloc::prelude::*; +use crate::alloc::{self, String}; use crate::hash::{Hash, IntoHash}; /// Struct representing a static string. -#[derive(Clone, Serialize, Deserialize)] +#[derive(Serialize, Deserialize)] pub struct StaticString { inner: String, hash: Hash, @@ -44,13 +44,13 @@ impl hash::Hash for StaticString { impl StaticString { /// Construct a new static string. - pub fn new(s: S) -> Self + pub fn new(s: S) -> alloc::Result where S: AsRef, { - let inner = s.as_ref().to_owned(); + let inner = s.as_ref().try_to_owned()?; let hash = s.as_ref().into_hash(); - Self { inner, hash } + Ok(Self { inner, hash }) } /// Get the hash of the string. diff --git a/crates/rune/src/runtime/static_type.rs b/crates/rune/src/runtime/static_type.rs index 811189a89..c1995610d 100644 --- a/crates/rune/src/runtime/static_type.rs +++ b/crates/rune/src/runtime/static_type.rs @@ -2,9 +2,9 @@ use core::cmp::{Eq, Ordering, PartialEq}; use core::hash; use core::ops::ControlFlow; -use crate::no_std::collections::HashMap; +use crate::no_std::std; -use crate::alloc; +use crate::alloc::{self, HashMap}; use crate::runtime as rt; use crate::runtime::{RawStr, TypeInfo}; use crate::Hash; @@ -141,6 +141,11 @@ pub(crate) static OBJECT_TYPE: &StaticType = &StaticType { }; impl_static_type!(rt::Struct => OBJECT_TYPE); +#[cfg(feature = "std")] +impl_static_type!(impl ::std::collections::HashMap => OBJECT_TYPE); +#[cfg(feature = "std")] +impl_static_type!(impl ::std::collections::HashMap => OBJECT_TYPE); +impl_static_type!(impl HashMap => OBJECT_TYPE); impl_static_type!(impl HashMap => OBJECT_TYPE); pub(crate) static RANGE_FROM_TYPE: &StaticType = &StaticType { diff --git a/crates/rune/src/runtime/to_value.rs b/crates/rune/src/runtime/to_value.rs index 20eaa726a..1652f5cf5 100644 --- a/crates/rune/src/runtime/to_value.rs +++ b/crates/rune/src/runtime/to_value.rs @@ -1,10 +1,10 @@ use core::any; use core::cmp::Ordering; -use crate::no_std::collections::HashMap; use crate::no_std::std; -use crate::alloc::{self, TryToString}; +use crate::alloc::prelude::*; +use crate::alloc::{self, HashMap}; use crate::runtime::{ AnyObj, Object, Shared, Value, VmError, VmErrorKind, VmIntegerRepr, VmResult, }; @@ -39,7 +39,7 @@ use crate::Any; /// let value: u64 = rune::from_value(value)?; /// /// assert_eq!(value, 43); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` pub use rune_macros::ToValue; @@ -71,7 +71,7 @@ pub use rune_macros::ToValue; /// let foo: u64 = rune::from_value(foo)?; /// /// assert_eq!(foo, 43); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` pub fn to_value(value: T) -> Result where @@ -108,7 +108,7 @@ where /// let foo: u64 = rune::from_value(foo)?; /// /// assert_eq!(foo, 43); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` pub trait ToValue: Sized { /// Convert into a value. @@ -290,6 +290,10 @@ macro_rules! impl_map { }; } +#[cfg(feature = "std")] +impl_map!(::std::collections::HashMap); +#[cfg(feature = "std")] +impl_map!(::std::collections::HashMap); impl_map!(HashMap); impl_map!(HashMap); diff --git a/crates/rune/src/runtime/tuple.rs b/crates/rune/src/runtime/tuple.rs index 37ba3d00d..f6a4d1d16 100644 --- a/crates/rune/src/runtime/tuple.rs +++ b/crates/rune/src/runtime/tuple.rs @@ -5,7 +5,8 @@ use core::slice; use crate::no_std::std; use crate as rune; -use crate::alloc::{Box, Error, Global, TryClone}; +use crate::alloc::clone::TryClone; +use crate::alloc::{self, Box}; use crate::runtime::{ ConstValue, FromValue, Mut, RawMut, RawRef, Ref, ToValue, UnsafeToMut, UnsafeToRef, Value, VmErrorKind, VmResult, @@ -136,14 +137,14 @@ impl Default for OwnedTuple { impl TryClone for OwnedTuple { #[inline] - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { inner: self.inner.try_clone()?, }) } #[inline] - fn try_clone_from(&mut self, source: &Self) -> Result<(), Error> { + fn try_clone_from(&mut self, source: &Self) -> alloc::Result<()> { self.inner.try_clone_from(&source.inner) } } @@ -185,7 +186,7 @@ impl ops::DerefMut for OwnedTuple { } impl TryFrom> for OwnedTuple { - type Error = Error; + type Error = alloc::Error; #[inline] fn try_from(vec: std::Vec) -> Result { @@ -196,7 +197,7 @@ impl TryFrom> for OwnedTuple { } impl TryFrom> for OwnedTuple { - type Error = Error; + type Error = alloc::Error; #[inline] fn try_from(vec: rune_alloc::Vec) -> Result { @@ -207,7 +208,7 @@ impl TryFrom> for OwnedTuple { } impl TryFrom<[Value; N]> for OwnedTuple { - type Error = Error; + type Error = alloc::Error; #[inline] fn try_from(values: [Value; N]) -> Result { @@ -218,10 +219,10 @@ impl TryFrom<[Value; N]> for OwnedTuple { } impl TryFrom> for OwnedTuple { - type Error = Error; + type Error = alloc::Error; #[inline] - fn try_from(inner: std::Box<[Value]>) -> Result { + fn try_from(inner: std::Box<[Value]>) -> alloc::Result { Ok(Self { inner: rune_alloc::Box::try_from(inner)?, }) @@ -236,14 +237,14 @@ impl From> for OwnedTuple { } impl TryFrom> for OwnedTuple { - type Error = Error; + type Error = alloc::Error; - fn try_from(inner: std::Box<[ConstValue]>) -> Result { + fn try_from(inner: std::Box<[ConstValue]>) -> alloc::Result { if inner.is_empty() { return Ok(OwnedTuple::new()); } - let mut out = rune_alloc::Vec::try_with_capacity_in(inner.len(), Global)?; + let mut out = rune_alloc::Vec::try_with_capacity(inner.len())?; for value in inner.into_vec() { out.try_push(value.into_value()?)?; @@ -256,14 +257,14 @@ impl TryFrom> for OwnedTuple { } impl TryFrom> for OwnedTuple { - type Error = Error; + type Error = alloc::Error; - fn try_from(inner: rune_alloc::Box<[ConstValue]>) -> Result { + fn try_from(inner: rune_alloc::Box<[ConstValue]>) -> alloc::Result { if inner.is_empty() { return Ok(OwnedTuple::new()); } - let mut out = rune_alloc::Vec::try_with_capacity_in(inner.len(), Global)?; + let mut out = rune_alloc::Vec::try_with_capacity(inner.len())?; for value in rune_alloc::Vec::from(inner) { out.try_push(value.into_value()?)?; diff --git a/crates/rune/src/runtime/type_info.rs b/crates/rune/src/runtime/type_info.rs index 8753564ae..8f083391a 100644 --- a/crates/rune/src/runtime/type_info.rs +++ b/crates/rune/src/runtime/type_info.rs @@ -1,12 +1,14 @@ use core::fmt; +use crate as rune; +use crate::alloc::prelude::*; use crate::hash::Hash; use crate::no_std::sync::Arc; use crate::runtime::{RawStr, Rtti, StaticType, VariantRtti}; /// Type information about a value, that can be printed for human consumption /// through its [Display][fmt::Display] implementation. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, TryClone, PartialEq, Eq)] #[non_exhaustive] pub enum TypeInfo { /// The static type of a value. @@ -53,7 +55,8 @@ impl fmt::Display for TypeInfo { } /// Type information for the [`Any`][crate::Any] type. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq)] +#[try_clone(copy)] #[non_exhaustive] pub struct AnyTypeInfo { /// The name of the type. diff --git a/crates/rune/src/runtime/unit.rs b/crates/rune/src/runtime/unit.rs index e95c7e785..e3aa5c63c 100644 --- a/crates/rune/src/runtime/unit.rs +++ b/crates/rune/src/runtime/unit.rs @@ -9,12 +9,14 @@ mod storage; use core::fmt; -use crate::no_std::prelude::*; use crate::no_std::sync::Arc; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, String, Vec}; use crate::hash; use crate::runtime::{ Call, ConstValue, DebugInfo, Inst, Rtti, StaticString, VariantRtti, VmError, VmErrorKind, @@ -36,8 +38,9 @@ pub type DefaultStorage = ArrayUnit; pub type DefaultStorage = ByteCodeUnit; /// Instructions and debug info from a single source file. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Debug, TryClone, Default, Serialize, Deserialize)] #[serde(bound = "S: Serialize + DeserializeOwned")] +#[try_clone(bound = {S: TryClone})] pub struct Unit { /// The information needed to execute the program. #[serde(flatten)] @@ -47,8 +50,9 @@ pub struct Unit { } /// Instructions from a single source file. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Debug, TryClone, Default, Serialize, Deserialize)] #[serde(rename = "Unit")] +#[try_clone(bound = {S: TryClone})] pub struct Logic { /// Storage for the unit. storage: S, @@ -75,11 +79,11 @@ pub struct Logic { impl Unit { /// Constructs a new unit from a pair of data and debug info. - pub fn from_parts(data: Logic, debug: Option) -> Self { - Self { + pub fn from_parts(data: Logic, debug: Option) -> alloc::Result { + Ok(Self { logic: data, - debug: debug.map(Box::new), - } + debug: debug.map(Box::try_new).transpose()?, + }) } /// Construct a new unit with the given content. @@ -268,6 +272,13 @@ pub(crate) enum UnitFn { }, } +impl TryClone for UnitFn { + #[inline] + fn try_clone(&self) -> alloc::Result { + Ok(*self) + } +} + impl fmt::Display for UnitFn { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/crates/rune/src/runtime/unit/byte_code.rs b/crates/rune/src/runtime/unit/byte_code.rs index b5b1bf68c..df47f4e7d 100644 --- a/crates/rune/src/runtime/unit/byte_code.rs +++ b/crates/rune/src/runtime/unit/byte_code.rs @@ -1,18 +1,20 @@ use core::mem::size_of; -use crate::no_std::vec::Vec; - use serde::{Deserialize, Serialize}; +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, Vec}; use crate::runtime::unit::{BadInstruction, BadJump, EncodeError, UnitEncoder, UnitStorage}; use crate::runtime::Inst; /// Unit stored as byte code, which is a more compact representation than /// [`ArrayUnit`], but takes more time to execute since it needs to be decoded. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Debug, TryClone, Default, Serialize, Deserialize)] pub struct ByteCodeUnit { /// The instructions contained in the source file. - bytes: Vec, + #[try_clone(with = Clone::clone)] + bytes: rust_alloc::vec::Vec, /// Known jump offsets. offsets: Vec, } @@ -51,10 +53,10 @@ impl UnitEncoder for ByteCodeUnit { } #[inline] - fn extend_offsets(&mut self, extra: usize) -> usize { + fn extend_offsets(&mut self, extra: usize) -> alloc::Result { let base = self.offsets.len(); - self.offsets.extend((0..extra).map(|_| 0)); - base + self.offsets.try_extend((0..extra).map(|_| 0))?; + Ok(base) } #[inline] diff --git a/crates/rune/src/runtime/unit/storage.rs b/crates/rune/src/runtime/unit/storage.rs index c7326fd9b..cfa50b885 100644 --- a/crates/rune/src/runtime/unit/storage.rs +++ b/crates/rune/src/runtime/unit/storage.rs @@ -3,8 +3,10 @@ use core::iter; use core::mem::size_of; use core::slice; +use crate as rune; +use crate::alloc::prelude::*; +use crate::alloc::{self, Vec}; use crate::no_std::error; -use crate::no_std::vec::Vec; #[cfg(feature = "byte-code")] use musli_storage::error::BufferError; @@ -33,7 +35,7 @@ pub trait UnitEncoder: self::sealed::Sealed { /// Indicate that the given number of offsets have been added. #[doc(hidden)] - fn extend_offsets(&mut self, extra: usize) -> usize; + fn extend_offsets(&mut self, extra: usize) -> alloc::Result; /// Mark that the given offset index is at the current offset. #[doc(hidden)] @@ -45,7 +47,7 @@ pub trait UnitEncoder: self::sealed::Sealed { } /// Instruction storage used by a [`Unit`][super::Unit]. -pub trait UnitStorage: self::sealed::Sealed + fmt::Debug + Default + Clone { +pub trait UnitStorage: self::sealed::Sealed + fmt::Debug + Default { /// Iterator over instructions and their corresponding instruction offsets. type Iter<'this>: Iterator where @@ -69,7 +71,7 @@ pub trait UnitStorage: self::sealed::Sealed + fmt::Debug + Default + Clone { } /// Unit stored as array of instructions. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Debug, TryClone, Default, Serialize, Deserialize)] pub struct ArrayUnit { instructions: Vec, } @@ -82,13 +84,13 @@ impl UnitEncoder for ArrayUnit { #[inline] fn encode(&mut self, inst: Inst) -> Result<(), EncodeError> { - self.instructions.push(inst); + self.instructions.try_push(inst)?; Ok(()) } #[inline] - fn extend_offsets(&mut self, _: usize) -> usize { - self.instructions.len() + fn extend_offsets(&mut self, _: usize) -> alloc::Result { + Ok(self.instructions.len()) } #[inline] @@ -150,15 +152,25 @@ impl From for EncodeError { } } +impl From for EncodeError { + #[inline] + fn from(error: alloc::Error) -> Self { + Self { + kind: EncodeErrorKind::AllocError { error }, + } + } +} + impl fmt::Display for EncodeError { #[inline] fn fmt( &self, #[cfg_attr(not(feature = "byte-code"), allow(unused))] f: &mut fmt::Formatter<'_>, ) -> fmt::Result { - match self.kind { + match &self.kind { #[cfg(feature = "byte-code")] - EncodeErrorKind::BufferError { ref error } => error.fmt(f), + EncodeErrorKind::BufferError { error } => error.fmt(f), + EncodeErrorKind::AllocError { error } => error.fmt(f), } } } @@ -168,7 +180,12 @@ impl error::Error for EncodeError {} #[derive(Debug)] enum EncodeErrorKind { #[cfg(feature = "byte-code")] - BufferError { error: BufferError }, + BufferError { + error: BufferError, + }, + AllocError { + error: alloc::Error, + }, } /// Error indicating that a bad instruction was located at the given instruction diff --git a/crates/rune/src/runtime/value.rs b/crates/rune/src/runtime/value.rs index bd517aa19..1eb86d978 100644 --- a/crates/rune/src/runtime/value.rs +++ b/crates/rune/src/runtime/value.rs @@ -9,7 +9,9 @@ use core::ptr; use crate::no_std::sync::Arc; -use crate::alloc::{self, Error, String, TryClone, TryToString, TryWrite}; +use crate::alloc::fmt::TryWrite; +use crate::alloc::prelude::*; +use crate::alloc::{self, String}; use crate::compile::ItemBuf; use crate::runtime::vm::CallResult; use crate::runtime::{ @@ -2148,7 +2150,7 @@ impl MaybeTypeOf for Value { } impl TryClone for Value { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { // NB: value cloning is a shallow clone of the underlying data. Ok(self.clone()) } diff --git a/crates/rune/src/runtime/value/serde.rs b/crates/rune/src/runtime/value/serde.rs index 5841515bd..2c385f3b2 100644 --- a/crates/rune/src/runtime/value/serde.rs +++ b/crates/rune/src/runtime/value/serde.rs @@ -1,6 +1,7 @@ use core::fmt; -use crate::alloc::{self, Global, TryToOwned}; +use crate::alloc; +use crate::alloc::prelude::*; use crate::no_std::std; use crate::runtime::{Bytes, Object, Shared, Vec}; @@ -141,8 +142,9 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { + let v = alloc::Vec::try_from(v).map_err(E::custom)?; Ok(Value::Bytes( - Shared::new(Bytes::from_vec(v.to_vec())).map_err(E::custom)?, + Shared::new(Bytes::from_vec(v)).map_err(E::custom)?, )) } @@ -151,6 +153,7 @@ impl<'de> de::Visitor<'de> for VmVisitor { where E: de::Error, { + let v = alloc::Vec::try_from(v).map_err(E::custom)?; Ok(Value::Bytes( Shared::new(Bytes::from_vec(v)).map_err(E::custom)?, )) @@ -292,9 +295,9 @@ impl<'de> de::Visitor<'de> for VmVisitor { V: de::SeqAccess<'de>, { let mut vec = if let Some(hint) = visitor.size_hint() { - alloc::Vec::try_with_capacity_in(hint, Global).map_err(V::Error::custom)? + alloc::Vec::try_with_capacity(hint).map_err(V::Error::custom)? } else { - alloc::Vec::new_in(Global) + alloc::Vec::new() }; while let Some(elem) = visitor.next_element()? { diff --git a/crates/rune/src/runtime/vec.rs b/crates/rune/src/runtime/vec.rs index 9f4163936..e06ec28a4 100644 --- a/crates/rune/src/runtime/vec.rs +++ b/crates/rune/src/runtime/vec.rs @@ -10,8 +10,9 @@ use core::slice::SliceIndex; use crate::no_std::std; use crate as rune; +use crate::alloc; use crate::alloc::fmt::TryWrite; -use crate::alloc::{self, Error, Global, TryClone}; +use crate::alloc::prelude::*; #[cfg(feature = "alloc")] use crate::runtime::Hasher; use crate::runtime::{ @@ -37,13 +38,13 @@ use self::iter::Iter; /// assert_eq!(Some(42), vec.get_value(0).into_result()?); /// assert_eq!(Some(true), vec.get_value(1).into_result()?); /// assert_eq!(None::, vec.get_value(2).into_result()?); -/// # Ok::<_, rune::Error>(()) +/// # Ok::<_, rune::support::Error>(()) /// ``` #[derive(Any)] #[repr(transparent)] #[rune(builtin, static_type = VEC_TYPE, from_value = Value::into_vec)] pub struct Vec { - inner: alloc::Vec, + inner: alloc::Vec, } impl Vec { @@ -60,7 +61,7 @@ impl Vec { /// ``` pub const fn new() -> Self { Self { - inner: alloc::Vec::new_in(Global), + inner: alloc::Vec::new(), } } @@ -74,14 +75,14 @@ impl Vec { /// Construct a new dynamic vector guaranteed to have at least the given /// capacity. - pub fn with_capacity(cap: usize) -> Result { + pub fn with_capacity(cap: usize) -> alloc::Result { Ok(Self { - inner: alloc::Vec::try_with_capacity_in(cap, Global)?, + inner: alloc::Vec::try_with_capacity(cap)?, }) } /// Convert into inner std vector. - pub fn into_inner(self) -> alloc::Vec { + pub fn into_inner(self) -> alloc::Vec { self.inner } @@ -128,7 +129,7 @@ impl Vec { } /// Appends an element to the back of a dynamic vector. - pub fn push(&mut self, value: Value) -> Result<(), Error> { + pub fn push(&mut self, value: Value) -> alloc::Result<()> { self.inner.try_push(value) } @@ -398,7 +399,7 @@ impl Vec { } impl TryClone for Vec { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { inner: self.inner.try_clone()?, }) @@ -458,11 +459,11 @@ impl<'a> IntoIterator for &'a mut Vec { } impl TryFrom> for Vec { - type Error = Error; + type Error = alloc::Error; #[inline] fn try_from(values: std::Vec) -> Result { - let mut inner = alloc::Vec::try_with_capacity_in(values.len(), Global)?; + let mut inner = alloc::Vec::try_with_capacity(values.len())?; for value in values { inner.try_push(value)?; @@ -473,7 +474,7 @@ impl TryFrom> for Vec { } impl TryFrom> for Vec { - type Error = Error; + type Error = alloc::Error; #[inline] fn try_from(inner: std::Box<[Value]>) -> Result { @@ -481,7 +482,7 @@ impl TryFrom> for Vec { } } -impl From> for Vec { +impl From> for Vec { #[inline] fn from(inner: alloc::Vec) -> Self { Self { inner } @@ -514,7 +515,7 @@ where let vec = vm_try!(value.into_vec()); let vec = vm_try!(vec.take()); - let mut output = vm_try!(alloc::Vec::try_with_capacity_in(vec.len(), Global)); + let mut output = vm_try!(alloc::Vec::try_with_capacity(vec.len())); for value in vec { vm_try!(output.try_push(vm_try!(T::from_value(value)))); @@ -536,12 +537,12 @@ impl UnsafeToRef for [Value] { } } -impl ToValue for alloc::Vec +impl ToValue for alloc::Vec where T: ToValue, { fn to_value(self) -> VmResult { - let mut inner = vm_try!(alloc::Vec::try_with_capacity_in(self.len(), Global)); + let mut inner = vm_try!(alloc::Vec::try_with_capacity(self.len())); for value in self { vm_try!(inner.try_push(vm_try!(value.to_value()))); @@ -556,7 +557,7 @@ where T: ToValue, { fn to_value(self) -> VmResult { - let mut inner = vm_try!(alloc::Vec::try_with_capacity_in(self.len(), Global)); + let mut inner = vm_try!(alloc::Vec::try_with_capacity(self.len())); for value in self { vm_try!(inner.try_push(vm_try!(value.to_value()))); diff --git a/crates/rune/src/runtime/vm.rs b/crates/rune/src/runtime/vm.rs index 5cbdb4d14..1836c69b9 100644 --- a/crates/rune/src/runtime/vm.rs +++ b/crates/rune/src/runtime/vm.rs @@ -3,11 +3,11 @@ use core::mem::{replace, swap}; use core::ops; use core::slice; -use crate::alloc::{Error, IteratorExt, String, TryClone, TryToOwned}; +use crate::alloc::prelude::*; +use crate::alloc::{self, String}; use crate::hash::{Hash, IntoHash, ToTypeHash}; use crate::modules::{option, result}; use crate::no_std::borrow::ToOwned; -use crate::no_std::std; use crate::no_std::sync::Arc; use crate::no_std::vec; use crate::runtime::budget; @@ -102,7 +102,7 @@ pub struct Vm { /// The current stack. stack: Stack, /// Frames relative to the stack. - call_frames: vec::Vec, + call_frames: alloc::Vec, } impl Vm { @@ -119,7 +119,7 @@ impl Vm { ip: 0, last_ip_len: 0, stack, - call_frames: vec::Vec::new(), + call_frames: alloc::Vec::new(), } } @@ -223,7 +223,7 @@ impl Vm { /// use std::sync::Arc; /// /// let context = Context::with_default_modules()?; - /// let context = Arc::new(context.runtime()); + /// let context = Arc::new(context.runtime()?); /// /// let mut sources = rune::sources! { /// entry => { @@ -249,15 +249,15 @@ impl Vm { /// assert_eq!(value, 20); /// /// // Building an item buffer to lookup an `::std` item. - /// let mut item = ItemBuf::with_crate("std"); - /// item.push("i64"); - /// item.push("max"); + /// let mut item = ItemBuf::with_crate("std")?; + /// item.push("i64")?; + /// item.push("max")?; /// /// let max = vm.lookup_function(&item)?; /// /// let value: i64 = rune::from_value(max.call((10, 20)).into_result()?)?; /// assert_eq!(value, 20); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn lookup_function(&self, name: N) -> Result where @@ -301,7 +301,7 @@ impl Vm { /// use std::sync::Arc; /// /// let context = Context::with_default_modules()?; - /// let context = Arc::new(context.runtime()); + /// let context = Arc::new(context.runtime()?); /// /// // Normally the unit would be created by compiling some source, /// // and since this one is empty it won't do anything. @@ -313,7 +313,7 @@ impl Vm { /// let output: i64 = rune::from_value(output)?; /// /// println!("output: {}", output); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` /// /// You can use a `Vec` to provide a variadic collection of @@ -324,7 +324,7 @@ impl Vm { /// use std::sync::Arc; /// /// let context = Context::with_default_modules()?; - /// let context = Arc::new(context.runtime()); + /// let context = Arc::new(context.runtime()?); /// /// // Normally the unit would be created by compiling some source, /// // and since this one is empty it won't do anything. @@ -340,7 +340,7 @@ impl Vm { /// let output: i64 = rune::from_value(output)?; /// /// println!("output: {}", output); - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn execute(&mut self, name: N, args: A) -> Result, VmError> where @@ -464,13 +464,13 @@ impl Vm { { let hash = name.to_type_hash(); - let info = self.unit.function(hash).ok_or_else(|| { - if let Some(item) = name.to_item() { + let Some(info) = self.unit.function(hash) else { + return Err(if let Some(item) = name.to_item()? { VmErrorKind::MissingEntry { hash, item } } else { VmErrorKind::MissingEntryHash { hash } - } - })?; + }); + }; let offset = match info { // NB: we ignore the calling convention. @@ -636,7 +636,7 @@ impl Vm { isolated, }; - self.call_frames.push(frame); + self.call_frames.try_push(frame)?; Ok(()) } @@ -2484,7 +2484,9 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_bytes(&mut self, slot: usize) -> VmResult<()> { - let bytes = vm_try!(self.unit.lookup_bytes(slot)).to_vec(); + let bytes = vm_try!(alloc::Vec::::try_from(vm_try!(self + .unit + .lookup_bytes(slot)))); vm_try!(self .stack .push(vm_try!(Value::try_from(Bytes::from_vec(bytes))))); @@ -2734,7 +2736,7 @@ impl Vm { #[cfg_attr(feature = "bench", inline(never))] fn op_match_object(&mut self, slot: usize, exact: bool) -> VmResult<()> { - fn test(object: &Object, keys: &[std::String], exact: bool) -> bool { + fn test(object: &Object, keys: &[alloc::String], exact: bool) -> bool { if exact { if object.len() != keys.len() { return false; @@ -3018,7 +3020,7 @@ impl Vm { /// use std::sync::Arc; /// /// let context = Context::with_default_modules()?; - /// let context = Arc::new(context.runtime()); + /// let context = Arc::new(context.runtime()?); /// /// // Normally the unit would be created by compiling some source, /// // and since this one is empty it'll just error. @@ -3036,7 +3038,7 @@ impl Vm { /// // Note: We do an extra unwrap because the return value is /// // `fmt::Result`. /// vm.with(|| output.string_display(&mut f)).into_result()?; - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn with(&mut self, f: F) -> T where @@ -3321,14 +3323,14 @@ impl Vm { } impl TryClone for Vm { - fn try_clone(&self) -> Result { + fn try_clone(&self) -> alloc::Result { Ok(Self { context: self.context.clone(), unit: self.unit.clone(), ip: self.ip, last_ip_len: self.last_ip_len, stack: self.stack.try_clone()?, - call_frames: self.call_frames.clone(), + call_frames: self.call_frames.try_clone()?, }) } } @@ -3366,6 +3368,13 @@ pub struct CallFrame { pub isolated: bool, } +impl TryClone for CallFrame { + #[inline] + fn try_clone(&self) -> alloc::Result { + Ok(*self) + } +} + /// Clear stack on drop. struct ClearStack<'a>(&'a mut Vm); diff --git a/crates/rune/src/runtime/vm_call.rs b/crates/rune/src/runtime/vm_call.rs index 92b38d47a..9e2708d43 100644 --- a/crates/rune/src/runtime/vm_call.rs +++ b/crates/rune/src/runtime/vm_call.rs @@ -1,6 +1,6 @@ use crate::no_std::sync::Arc; -use crate::alloc::IteratorExt; +use crate::alloc::prelude::*; use crate::runtime::vm_execution::VmExecutionState; use crate::runtime::{ Call, Future, Generator, RuntimeContext, Stack, Stream, Unit, Value, Vm, VmErrorKind, diff --git a/crates/rune/src/runtime/vm_error.rs b/crates/rune/src/runtime/vm_error.rs index 8e7bdc142..b30965f4e 100644 --- a/crates/rune/src/runtime/vm_error.rs +++ b/crates/rune/src/runtime/vm_error.rs @@ -4,7 +4,8 @@ use core::fmt; use crate::no_std::prelude::*; use crate::no_std::sync::Arc; -use crate::alloc::{AllocError, CustomError, Error}; +use crate::alloc; +use crate::alloc::error::CustomError; use crate::compile::ItemBuf; use crate::hash::Hash; use crate::runtime::unit::{BadInstruction, BadJump}; @@ -647,11 +648,8 @@ pub(crate) enum VmErrorKind { }, MissingCallFrame, IllegalFormat, - TryReserveError { - error: Error, - }, AllocError { - error: AllocError, + error: alloc::Error, }, } @@ -855,12 +853,6 @@ impl fmt::Display for VmErrorKind { VmErrorKind::IllegalFormat => { write!(f, "Value cannot be formatted") } - VmErrorKind::TryReserveError { error } => { - write!( - f, - "Failed to allocate memory for the current operation: {error}" - ) - } VmErrorKind::AllocError { error } => error.fmt(f), } } @@ -901,17 +893,19 @@ impl From for VmErrorKind { } } -impl From for VmErrorKind { +impl From for VmErrorKind { #[inline] - fn from(error: Error) -> Self { - VmErrorKind::TryReserveError { error } + fn from(error: alloc::Error) -> Self { + VmErrorKind::AllocError { error } } } -impl From for VmErrorKind { +impl From for VmErrorKind { #[inline] - fn from(error: AllocError) -> Self { - VmErrorKind::AllocError { error } + fn from(error: alloc::alloc::AllocError) -> Self { + VmErrorKind::AllocError { + error: error.into(), + } } } diff --git a/crates/rune/src/runtime/vm_execution.rs b/crates/rune/src/runtime/vm_execution.rs index fa7d87053..214f5ce23 100644 --- a/crates/rune/src/runtime/vm_execution.rs +++ b/crates/rune/src/runtime/vm_execution.rs @@ -101,7 +101,7 @@ where /// assert_eq!(value, n); /// n += 1; /// } - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn into_generator(self) -> Generator { Generator::from_execution(self) @@ -135,9 +135,9 @@ where /// assert_eq!(value, n); /// n += 1; /// } - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// # })?; - /// # Ok::<_, rune::Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn into_stream(self) -> Stream { Stream::from_execution(self) diff --git a/crates/rune/src/shared/consts.rs b/crates/rune/src/shared/consts.rs index 10ddb94b4..6b3b937df 100644 --- a/crates/rune/src/shared/consts.rs +++ b/crates/rune/src/shared/consts.rs @@ -3,8 +3,7 @@ //! This maps the item of a global constant to its value. It's also used to //! detect resolution cycles during constant evaluation. -use crate::no_std::collections::{HashMap, HashSet}; - +use crate::alloc::{self, HashMap, HashSet}; use crate::compile::ItemId; use crate::runtime::ConstValue; @@ -22,8 +21,8 @@ impl Consts { /// /// Returns `true` if the given constant hasn't been marked yet. This is /// used to detect cycles during processing. - pub(crate) fn mark(&mut self, item: ItemId) -> bool { - self.processing.insert(item) + pub(crate) fn mark(&mut self, item: ItemId) -> alloc::Result { + self.processing.try_insert(item) } /// Get the value for the constant at the given item, if present. @@ -32,7 +31,11 @@ impl Consts { } /// Insert a constant value at the given item. - pub(crate) fn insert(&mut self, item: ItemId, value: ConstValue) -> Option { - self.resolved.insert(item, value) + pub(crate) fn insert( + &mut self, + item: ItemId, + value: ConstValue, + ) -> alloc::Result> { + self.resolved.try_insert(item, value) } } diff --git a/crates/rune/src/source.rs b/crates/rune/src/source.rs index 36de5d398..506e599db 100644 --- a/crates/rune/src/source.rs +++ b/crates/rune/src/source.rs @@ -6,8 +6,8 @@ use core::iter; use core::ops::Range; use core::slice; +use crate::alloc::path::Path; use crate::no_std::io; -use crate::no_std::path::Path; use crate::no_std::prelude::*; #[cfg(feature = "emit")] diff --git a/crates/rune/src/sources.rs b/crates/rune/src/sources.rs index fac8aa423..5a7e961c1 100644 --- a/crates/rune/src/sources.rs +++ b/crates/rune/src/sources.rs @@ -1,9 +1,10 @@ use core::fmt; use core::num; -use crate::no_std::path::Path; -use crate::no_std::prelude::*; - +use crate as rune; +use crate::alloc::path::Path; +use crate::alloc::prelude::*; +use crate::alloc::{self, Vec}; use crate::ast::Span; use crate::source::Source; #[cfg(feature = "codespan-reporting")] @@ -12,6 +13,9 @@ use codespan_reporting::files; /// Helper macro to define a collection of sources populatedc with the given /// entries. /// +/// Calling this macro is fallible with [alloc::Error], so you should do it in a +/// function that returns a `Result`. +/// /// ``` /// let sources = rune::sources! { /// entry => { @@ -20,12 +24,14 @@ use codespan_reporting::files; /// } /// } /// }; +/// +/// Ok::<_, rune::support::Error>(()) /// ``` #[macro_export] macro_rules! sources { ($($name:ident => {$($tt:tt)*}),* $(,)?) => {{ let mut sources = $crate::Sources::new(); - $(sources.insert($crate::Source::new(stringify!($name), stringify!($($tt)*)));)* + $(sources.insert($crate::Source::new(stringify!($name), stringify!($($tt)*)))?;)* sources }}; } @@ -57,11 +63,11 @@ impl Sources { /// let id2 = sources.insert(Source::new("", "pub fn main() { 10 }")); /// assert_ne!(id, id2); /// ``` - pub fn insert(&mut self, source: Source) -> SourceId { + pub fn insert(&mut self, source: Source) -> alloc::Result { let id = SourceId::try_from(self.sources.len()).expect("could not build a source identifier"); - self.sources.push(source); - id + self.sources.try_push(source)?; + Ok(id) } /// Get the source matching the given source id. @@ -69,16 +75,16 @@ impl Sources { /// # Examples /// /// ``` - /// # use anyhow::{Context, Error}; + /// # use anyhow::Context; /// use rune::{Sources, Source}; /// /// let mut sources = Sources::new(); - /// let id = sources.insert(Source::new("", "pub fn main() { 10 }")); + /// let id = sources.insert(Source::new("", "pub fn main() { 10 }"))?; /// /// let source = sources.get(id).context("expected source")?; /// /// assert_eq!(source.name(), ""); - /// # Ok::<_, Error>(()) + /// # Ok::<_, rune::support::Error>(()) /// ``` pub fn get(&self, id: SourceId) -> Option<&Source> { self.sources.get(id.into_index()) @@ -158,7 +164,8 @@ impl<'a> files::Files<'a> for Sources { /// /// It can be used to reference the inserted source file in the future through /// methods such as [`Sources::get`]. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(TryClone, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[try_clone(copy)] #[repr(transparent)] pub struct SourceId { index: u32, diff --git a/crates/rune/src/support.rs b/crates/rune/src/support.rs new file mode 100644 index 000000000..750f36fcf --- /dev/null +++ b/crates/rune/src/support.rs @@ -0,0 +1,149 @@ +//! This module is primarily provided to support test cases and examples. It is +//! not intended for end-users and might change at any time. + +#[doc(inline)] +pub use anyhow::Context; + +#[cfg(not(feature = "std"))] +#[doc(inline)] +pub use self::no_std::{Error, Result}; +#[cfg(feature = "std")] +#[doc(inline)] +pub use anyhow::{Error, Result}; + +#[cfg(not(feature = "std"))] +pub(crate) mod no_std { + use core::fmt; + + use crate::alloc; + use crate::build; + use crate::compile; + use crate::runtime; + #[cfg(test)] + use crate::tests; + + /// Type alias for for results which uses [`Error`] by default. + /// + /// For errors which aren't automatically captures, you should map them + /// using [`Error::msg`]. + pub type Result = ::core::result::Result; + + /// Error kind which supports capturing any toplevel errors produced by + /// Rune. + #[derive(Debug)] + pub struct Error { + kind: ErrorKind, + } + + impl Error { + /// Create a new error object from a printable error message. + pub fn msg(message: M) -> Self + where + M: fmt::Display + fmt::Debug + Send + Sync + 'static, + { + Self { + kind: ErrorKind::Custom(anyhow::Error::msg(message)), + } + } + } + + impl From for Error { + fn from(error: alloc::Error) -> Self { + Self { + kind: ErrorKind::Alloc(error), + } + } + } + + impl From for Error { + fn from(error: compile::ContextError) -> Self { + Self { + kind: ErrorKind::Context(error), + } + } + } + + impl From for Error { + fn from(error: compile::Error) -> Self { + Self { + kind: ErrorKind::Compile(error), + } + } + } + + impl From for Error { + fn from(error: build::BuildError) -> Self { + Self { + kind: ErrorKind::Build(error), + } + } + } + + impl From for Error { + fn from(error: runtime::VmError) -> Self { + Self { + kind: ErrorKind::Vm(error), + } + } + } + + impl From for Error { + fn from(error: anyhow::Error) -> Self { + Self { + kind: ErrorKind::Custom(error), + } + } + } + + #[cfg(test)] + impl From for Error { + fn from(error: tests::RunError) -> Self { + Self { + kind: ErrorKind::Test(error), + } + } + } + + impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.kind { + ErrorKind::Alloc(error) => error.fmt(f), + ErrorKind::Context(error) => error.fmt(f), + ErrorKind::Compile(error) => error.fmt(f), + ErrorKind::Build(error) => error.fmt(f), + ErrorKind::Vm(error) => error.fmt(f), + ErrorKind::Custom(error) => error.fmt(f), + #[cfg(test)] + ErrorKind::Test(error) => error.fmt(f), + } + } + } + + #[derive(Debug)] + enum ErrorKind { + Alloc(alloc::Error), + Context(compile::ContextError), + Compile(compile::Error), + Build(build::BuildError), + Vm(runtime::VmError), + Custom(anyhow::Error), + #[cfg(test)] + Test(tests::RunError), + } + + #[cfg(feature = "std")] + impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self.kind { + ErrorKind::Alloc(error) => Some(error), + ErrorKind::Context(error) => Some(error), + ErrorKind::Compile(error) => Some(error), + ErrorKind::Build(error) => Some(error), + ErrorKind::Vm(error) => Some(error), + ErrorKind::Custom(error) => Some(error.as_ref()), + #[cfg(test)] + ErrorKind::Test(error) => Some(error), + } + } + } +} diff --git a/crates/rune/src/testing.rs b/crates/rune/src/testing.rs index dd78eb1a7..e60ecce32 100644 --- a/crates/rune/src/testing.rs +++ b/crates/rune/src/testing.rs @@ -2,7 +2,7 @@ use core::fmt; -use crate::macros::{MacroContext, ToTokens, TokenStream}; +use crate::macros::{self, ToTokens, TokenStream}; use crate::parse::{Parse, Parser}; use crate::SourceId; @@ -39,14 +39,15 @@ where let ast = expect!(parser.parse::(), "first parse"); expect!(parser.eof(), "First parse EOF"); - let ast2 = MacroContext::test(|cx| { + let ast2 = macros::test(|cx| { let mut stream = TokenStream::new(); - ast.to_tokens(cx, &mut stream); + ast.to_tokens(cx, &mut stream)?; let mut parser = Parser::from_token_stream(&stream, cx.input_span()); let ast2 = expect!(parser.parse::(), "Second parse"); expect!(parser.eof(), "Second parse EOF"); - ast2 - }); + Ok(ast2) + }) + .unwrap(); assert_eq!(ast, ast2); ast diff --git a/crates/rune/src/tests.rs b/crates/rune/src/tests.rs index 5f5f7cd54..73a3c3bb5 100644 --- a/crates/rune/src/tests.rs +++ b/crates/rune/src/tests.rs @@ -5,7 +5,8 @@ pub(crate) mod prelude { pub(crate) use crate as rune; - pub(crate) use crate::alloc::{self, TryClone}; + pub(crate) use crate::alloc; + pub(crate) use crate::alloc::prelude::*; pub(crate) use crate::ast; pub(crate) use crate::compile::{self, ErrorKind, Item, ItemBuf, Located, Named}; pub(crate) use crate::diagnostics; @@ -17,10 +18,11 @@ pub(crate) mod prelude { OwnedTuple, Protocol, RawRef, RawStr, Ref, Shared, Stack, Tuple, TypeInfo, TypeOf, UnsafeToRef, VecTuple, VmErrorKind, VmResult, }; + pub(crate) use crate::support::Result; pub(crate) use crate::tests::run; pub(crate) use crate::{ from_value, prepare, sources, span, vm_try, Any, Context, ContextError, Diagnostics, - FromValue, Hash, Module, Result, Source, Sources, ToValue, Value, Vm, + FromValue, Hash, Module, Source, Sources, ToValue, Value, Vm, }; pub(crate) use futures_executor::block_on; } @@ -32,6 +34,7 @@ use crate::no_std::sync::Arc; use anyhow::{Context as _, Error, Result}; +use crate::alloc; use crate::compile::{IntoComponent, ItemBuf}; use crate::runtime::{Args, VmError, VmResult}; use crate::{termcolor, BuildError, Context, Diagnostics, FromValue, Source, Sources, Unit, Vm}; @@ -43,6 +46,8 @@ pub enum RunError { BuildError(String), /// A virtual machine error was raised during testing. VmError(VmError), + /// Allocation error. + AllocError(alloc::Error), } impl fmt::Display for RunError { @@ -50,6 +55,18 @@ impl fmt::Display for RunError { match self { RunError::BuildError(error) => write!(f, "Build error: {error}"), RunError::VmError(error) => write!(f, "Vm error: {error}"), + RunError::AllocError(error) => write!(f, "Allocation error: {error}"), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for RunError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + RunError::VmError(error) => Some(error), + RunError::AllocError(error) => Some(error), + _ => None, } } } @@ -60,7 +77,7 @@ pub fn compile_helper(source: &str, diagnostics: &mut Diagnostics) -> Result Sources { let mut sources = Sources::new(); - sources.insert(Source::new("main", source)); + sources + .insert(Source::new("main", source)) + .expect("Failed to insert source"); sources } @@ -148,7 +167,7 @@ where T: FromValue, { let mut sources = Sources::new(); - sources.insert(Source::new("main", source)); + sources.insert(Source::new("main", source))?; let mut diagnostics = Default::default(); @@ -166,6 +185,7 @@ where String::from_utf8(buffer.into_inner()).context("Decode output as utf-8")?; Err(Error::msg(buffer)) } + RunError::AllocError(error) => Err(Error::from(error)), } } diff --git a/crates/rune/src/tests/attribute.rs b/crates/rune/src/tests/attribute.rs index b7272e72b..5dc94c316 100644 --- a/crates/rune/src/tests/attribute.rs +++ b/crates/rune/src/tests/attribute.rs @@ -85,8 +85,8 @@ fn deny_nested_bench() { fn deny_struct_attributes() { assert_errors! { "#[struct_attribute] struct Struct {}", - span!(0, 19), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on structs are not supported"); + span!(0, 19), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on structs are not supported"); } } } @@ -95,8 +95,8 @@ fn deny_struct_attributes() { fn deny_enum_attributes() { assert_errors! { "#[enum_attribute] enum Enum {}", - span!(0, 17), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on enums are not supported"); + span!(0, 17), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on enums are not supported"); } } } @@ -105,8 +105,8 @@ fn deny_enum_attributes() { fn deny_fn_attributes() { assert_errors! { "#[function_attribute] fn function() {}", - span!(0, 21), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on functions are not supported"); + span!(0, 21), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on functions are not supported"); } } } @@ -115,8 +115,8 @@ fn deny_fn_attributes() { fn deny_const_attributes() { assert_errors! { "#[constant_attribute] const CONSTANT = 42;", - span!(0, 21), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on constants are not supported"); + span!(0, 21), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on constants are not supported"); } } } @@ -125,8 +125,8 @@ fn deny_const_attributes() { fn deny_use_attributes() { assert_errors! { "#[use_attribute] use std::str;", - span!(0, 16), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on uses are not supported"); + span!(0, 16), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on uses are not supported"); } } } @@ -135,8 +135,8 @@ fn deny_use_attributes() { fn deny_mod_attributes() { assert_errors! { "#[mod_attribute] mod inner {}", - span!(0, 16), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on modules are not supported"); + span!(0, 16), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on modules are not supported"); } } } @@ -145,8 +145,8 @@ fn deny_mod_attributes() { fn deny_local_attributes() { assert_errors! { "pub fn main() { #[local_attribute] let x = 1; }", - span!(16, 34), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on local declarations are not supported"); + span!(16, 34), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on local declarations are not supported"); } }; } @@ -155,8 +155,8 @@ fn deny_local_attributes() { fn deny_block_attributes() { assert_errors! { r#"pub fn main() { #[block_attribute] {} }"#, - span!(16, 34), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on blocks are not supported"); + span!(16, 34), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on blocks are not supported"); } }; } @@ -165,8 +165,8 @@ fn deny_block_attributes() { fn deny_macro_attributes() { assert_errors! { r#"#[macro_attribute] macro_call!()"#, - span!(0, 18), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on macros are not supported"); + span!(0, 18), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on macros are not supported"); } }; } @@ -175,8 +175,8 @@ fn deny_macro_attributes() { fn deny_field_attributes() { assert_errors! { r#"struct Struct { #[field_attribute] field }"#, - span!(16, 34), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on fields are not supported"); + span!(16, 34), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on fields are not supported"); } }; } @@ -185,8 +185,8 @@ fn deny_field_attributes() { fn deny_variant_attributes() { assert_errors! { r#"enum Enum { #[field_attribute] Variant }"#, - span!(12, 30), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on variants are not supported"); + span!(12, 30), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on variants are not supported"); } }; } @@ -195,8 +195,8 @@ fn deny_variant_attributes() { fn deny_variant_field_attributes() { assert_errors! { r#"enum Enum { Variant { #[field_attribute] field } }"#, - span!(22, 40), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on variant fields are not supported"); + span!(22, 40), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on variant fields are not supported"); } }; } @@ -205,8 +205,8 @@ fn deny_variant_field_attributes() { fn deny_expr_attributes() { assert_errors! { r#"pub fn main() { #[expr_attribute] 42 }"#, - span!(16, 33), Custom { message } => { - assert_eq!(message.as_ref(), "Attributes on expressions are not supported"); + span!(16, 33), Custom { error } => { + assert_eq!(error.to_string(), "Attributes on expressions are not supported"); } }; } diff --git a/crates/rune/src/tests/bug_326.rs b/crates/rune/src/tests/bug_326.rs index 2e91f3671..0e3809c71 100644 --- a/crates/rune/src/tests/bug_326.rs +++ b/crates/rune/src/tests/bug_326.rs @@ -9,7 +9,7 @@ fn bug_326() -> Result<()> { let mut context = Context::with_default_modules()?; context.install(trim_module()?)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = Sources::new(); sources.insert(Source::new( @@ -25,7 +25,7 @@ fn bug_326() -> Result<()> { println(template_runtime_failure); } "#, - )); + ))?; let result = prepare(&mut sources).with_context(&context).build(); @@ -37,7 +37,7 @@ fn bug_326() -> Result<()> { } fn trim_module() -> Result { - let mut m = Module::with_item(["mymodule"]); + let mut m = Module::with_item(["mymodule"])?; m.function_meta(trim_indent)?; Ok(m) } diff --git a/crates/rune/src/tests/bug_344.rs b/crates/rune/src/tests/bug_344.rs index 72fc5f7bf..29f5f25ec 100644 --- a/crates/rune/src/tests/bug_344.rs +++ b/crates/rune/src/tests/bug_344.rs @@ -20,7 +20,7 @@ fn bug_344_function() -> Result<()> { module.function(["function"], function)?; context.install(module)?; - let runtime = context.runtime(); + let runtime = context.runtime()?; let hash = Hash::type_hash(["function"]); @@ -54,7 +54,7 @@ fn bug_344_inst_fn() -> Result<()> { module.function_meta(function)?; context.install(module)?; - let runtime = context.runtime(); + let runtime = context.runtime()?; let hash = Hash::associated_function(::type_hash(), "function"); @@ -77,7 +77,7 @@ fn bug_344_async_function() -> Result<()> { module.function(["function"], function)?; context.install(module)?; - let runtime = context.runtime(); + let runtime = context.runtime()?; let hash = Hash::type_hash(["function"]); @@ -121,7 +121,7 @@ fn bug_344_async_inst_fn() -> Result<()> { module.function_meta(function)?; context.install(module)?; - let runtime = context.runtime(); + let runtime = context.runtime()?; let hash = Hash::associated_function(::type_hash(), "function"); diff --git a/crates/rune/src/tests/compiler_docs.rs b/crates/rune/src/tests/compiler_docs.rs index 3741d8925..f70437f53 100644 --- a/crates/rune/src/tests/compiler_docs.rs +++ b/crates/rune/src/tests/compiler_docs.rs @@ -8,11 +8,18 @@ struct DocVisitor { } impl compile::CompileVisitor for DocVisitor { - fn visit_doc_comment(&mut self, _: &dyn Located, item: &Item, _: Hash, doc: &str) { + fn visit_doc_comment( + &mut self, + _: &dyn Located, + item: &Item, + _: Hash, + doc: &str, + ) -> Result<(), compile::MetaError> { self.collected .entry(item.to_string()) .or_default() .push(doc.to_string()); + Ok(()) } fn visit_field_doc_comment( @@ -22,11 +29,12 @@ impl compile::CompileVisitor for DocVisitor { _: Hash, field: &str, doc: &str, - ) { + ) -> Result<(), compile::MetaError> { self.collected .entry(format!("{item}.{field}")) .or_default() .push(doc.to_string()); + Ok(()) } } @@ -88,7 +96,7 @@ macro_rules! expect_docs { } #[test] -fn harvest_docs() { +fn harvest_docs() -> Result<()> { let mut diagnostics = Diagnostics::new(); let mut vis = expect_docs! { "{root}" => { @@ -188,12 +196,12 @@ fn harvest_docs() { let context = Context::default(); - let result = prepare(&mut sources) + let _ = prepare(&mut sources) .with_context(&context) .with_diagnostics(&mut diagnostics) - .with_visitor(&mut vis) - .build(); + .with_visitor(&mut vis)? + .build()?; - result.unwrap(); vis.assert(); + Ok(()) } diff --git a/crates/rune/src/tests/compiler_patterns.rs b/crates/rune/src/tests/compiler_patterns.rs index 6fded2cb1..c97782c5f 100644 --- a/crates/rune/src/tests/compiler_patterns.rs +++ b/crates/rune/src/tests/compiler_patterns.rs @@ -3,7 +3,7 @@ prelude!(); use ErrorKind::*; #[test] -fn illegal_pattern_in_match() { +fn illegal_pattern_in_match() -> rune::support::Result<()> { assert_errors! { r#" struct Foo { bar, baz } @@ -13,7 +13,9 @@ fn illegal_pattern_in_match() { } "#, span!(81, 88), PatternMissingFields { fields, .. } => { - assert_eq!(&fields[..], [Box::from("bar"), Box::from("baz")]); + assert_eq!(fields.len(), 2); + assert_eq!(fields[0].as_ref(), "bar"); + assert_eq!(fields[1].as_ref(), "baz"); } }; @@ -26,7 +28,10 @@ fn illegal_pattern_in_match() { } "#, span!(81, 92), PatternMissingFields { fields, .. } => { - assert_eq!(&fields[..], [Box::from("baz")]); + assert_eq!(fields.len(), 1); + assert_eq!(fields[0].as_ref(), "baz"); } }; + + Ok(()) } diff --git a/crates/rune/src/tests/custom_macros.rs b/crates/rune/src/tests/custom_macros.rs index c85e5f8b7..39c5272b5 100644 --- a/crates/rune/src/tests/custom_macros.rs +++ b/crates/rune/src/tests/custom_macros.rs @@ -13,20 +13,20 @@ fn test_parse_in_macro() -> Result<()> { let string = "1 + 2 + 13 * 3"; m.macro_(["string_as_code"], move |cx, _| { - let id = cx.insert_source("string_as_code", string); + let id = cx.insert_source("string_as_code", string)?; let expr = cx.parse_source::(id)?; - Ok(quote!(#expr).into_token_stream(cx)) + Ok(quote!(#expr).into_token_stream(cx)?) })?; m.macro_(["string_as_code_from_arg"], |cx, stream| { let mut p = Parser::from_token_stream(stream, cx.input_span()); let s = p.parse_all::()?; - let s = cx.resolve(s)?.into_owned(); - let id = cx.insert_source("string_as_code_from_arg", &s); + let s = cx.resolve(s)?.try_into_owned()?; + let id = cx.insert_source("string_as_code_from_arg", &s)?; let expr = cx.parse_source::(id)?; - Ok(quote!(#expr).into_token_stream(cx)) + Ok(quote!(#expr).into_token_stream(cx)?) })?; let mut context = Context::with_default_modules()?; @@ -44,7 +44,7 @@ fn test_parse_in_macro() -> Result<()> { let unit = prepare(&mut sources).with_context(&context).build()?; - let mut vm = Vm::new(Arc::new(context.runtime()), Arc::new(unit)); + let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); let output = vm.call(["main"], ())?; let output: (u32, u32) = from_value(output)?; @@ -57,16 +57,17 @@ fn conflicting_attribute_function() -> Result<()> { let mut m = Module::default(); m.macro_(["conflicting"], move |cx, _| { - Ok(quote!(21).into_token_stream(cx)) + Ok(quote!(21).into_token_stream(cx)?) })?; m.attribute_macro(["conflicting"], |cx, _, _| { - Ok(quote!( + let stream = quote!( fn hello() { 21 } - ) - .into_token_stream(cx)) + ); + + Ok(stream.into_token_stream(cx)?) })?; let mut context = Context::with_default_modules()?; @@ -85,7 +86,7 @@ fn conflicting_attribute_function() -> Result<()> { let unit = prepare(&mut sources).with_context(&context).build()?; - let mut vm = Vm::new(Arc::new(context.runtime()), Arc::new(unit)); + let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); let output = vm.call(["main"], ())?; let output: u32 = from_value(output)?; @@ -95,24 +96,26 @@ fn conflicting_attribute_function() -> Result<()> { #[test] fn attribute_imports_builtin() -> Result<()> { - let mut m = Module::with_crate("abc"); + let mut m = Module::with_crate("abc")?; m.attribute_macro(["before_use"], |cx, _, _| { - Ok(quote!( + let stream = quote!( fn before() { 21 } - ) - .into_token_stream(cx)) + ); + + Ok(stream.into_token_stream(cx)?) })?; m.attribute_macro(["after_use"], |cx, _, _| { - Ok(quote!( + let stream = quote!( fn after() { 21 } - ) - .into_token_stream(cx)) + ); + + Ok(stream.into_token_stream(cx)?) })?; let mut context = Context::with_default_modules()?; @@ -150,7 +153,7 @@ fn attribute_imports_builtin() -> Result<()> { let unit = result?; - let mut vm = Vm::new(Arc::new(context.runtime()), Arc::new(unit)); + let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); let output = vm.call(["main"], ())?; let output: u32 = from_value(output)?; diff --git a/crates/rune/src/tests/external_constructor.rs b/crates/rune/src/tests/external_constructor.rs index 4ff72fb6c..af10fcee9 100644 --- a/crates/rune/src/tests/external_constructor.rs +++ b/crates/rune/src/tests/external_constructor.rs @@ -8,7 +8,7 @@ use rune::{Any, Context, ContextError, Module, Vm}; /// Tests pattern matching and constructing over an external variant from within /// Rune. #[test] -fn construct_enum() { +fn construct_enum() -> rune::support::Result<()> { #[derive(Debug, Any, PartialEq, Eq)] enum Enum { #[rune(constructor)] @@ -33,11 +33,11 @@ fn construct_enum() { Ok(module) } - let m = make_module().expect("Module should be buildable"); + let m = make_module()?; let mut context = Context::new(); - context.install(m).expect("Context should build"); - let runtime = Arc::new(context.runtime()); + context.install(m)?; + let runtime = Arc::new(context.runtime()?); let mut sources = sources! { entry => { @@ -53,34 +53,32 @@ fn construct_enum() { } }; - let unit = prepare(&mut sources) - .with_context(&context) - .build() - .expect("Unit should build"); + let unit = prepare(&mut sources).with_context(&context).build()?; let mut vm = Vm::new(runtime, Arc::new(unit)); - let output = vm.call(["main"], (Enum::First(42),)).unwrap(); - let output: Enum = from_value(output).unwrap(); + let output = vm.call(["main"], (Enum::First(42),))?; + let output: Enum = from_value(output)?; assert_eq!(output, Enum::Output(42)); - let output = vm.call(["main"], (Enum::Second(43),)).unwrap(); - let output: Enum = from_value(output).unwrap(); + let output = vm.call(["main"], (Enum::Second(43),))?; + let output: Enum = from_value(output)?; assert_eq!(output, Enum::Output(43 * 2)); - let output = vm.call(["main"], (Enum::Third,)).unwrap(); - let output: Enum = from_value(output).unwrap(); + let output = vm.call(["main"], (Enum::Third,))?; + let output: Enum = from_value(output)?; assert_eq!(output, Enum::Output(3)); - let output = vm.call(["main"], (Enum::Fourth { a: 2, b: 3 },)).unwrap(); - let output: Enum = from_value(output).unwrap(); + let output = vm.call(["main"], (Enum::Fourth { a: 2, b: 3 },))?; + let output: Enum = from_value(output)?; assert_eq!(output, Enum::Output(2 * 3 * 4)); + Ok(()) } /// Tests constructing an external struct from within Rune, and receiving /// external structs as an argument. #[test] -fn construct_struct() { +fn construct_struct() -> rune::support::Result<()> { #[derive(Debug, Any, PartialEq, Eq)] #[rune(constructor)] struct Request { @@ -116,11 +114,11 @@ fn construct_struct() { Ok(module) } - let m = make_module().expect("Module should be buildable"); + let m = make_module()?; let mut context = Context::new(); - context.install(m).expect("Context should build"); - let runtime = Arc::new(context.runtime()); + context.install(m)?; + let runtime = Arc::new(context.runtime()?); let mut sources = sources! { entry => { @@ -162,10 +160,7 @@ fn construct_struct() { } }; - let unit = prepare(&mut sources) - .with_context(&context) - .build() - .expect("Unit should build"); + let unit = prepare(&mut sources).with_context(&context).build()?; let mut vm = Vm::new(runtime, Arc::new(unit)); @@ -208,8 +203,10 @@ fn construct_struct() { }, ), ] { - let output = vm.call(["main"], (req,)).unwrap(); - let output: Response = from_value(output).unwrap(); + let output = vm.call(["main"], (req,))?; + let output: Response = from_value(output)?; assert_eq!(output, rsp); } + + Ok(()) } diff --git a/crates/rune/src/tests/external_generic.rs b/crates/rune/src/tests/external_generic.rs index 9cb2c4971..6b02291cc 100644 --- a/crates/rune/src/tests/external_generic.rs +++ b/crates/rune/src/tests/external_generic.rs @@ -31,7 +31,7 @@ where } fn make_native_module() -> Result { - let mut module = Module::with_crate("native_crate"); + let mut module = Module::with_crate("native_crate")?; module.ty::>()?; module.associated_function("get_value", Generic::::get_value)?; @@ -57,7 +57,7 @@ fn compile(mut sources: Sources) -> Result { } let unit = result?; - Ok(Vm::new(Arc::new(context.runtime()), Arc::new(unit))) + Ok(Vm::new(Arc::new(context.runtime()?), Arc::new(unit))) } // This is similar to the generic test that existed before, but ensures that the diff --git a/crates/rune/src/tests/external_ops.rs b/crates/rune/src/tests/external_ops.rs index c6599a2f7..8b1cb2c8b 100644 --- a/crates/rune/src/tests/external_ops.rs +++ b/crates/rune/src/tests/external_ops.rs @@ -51,7 +51,7 @@ fn assign_ops_struct() -> Result<()> { number.custom {op} {arg}; }} "#, op = stringify!($($op)*), arg = stringify!($arg)), - )); + ))?; let unit = prepare(&mut sources) .with_context(&context) @@ -59,7 +59,7 @@ fn assign_ops_struct() -> Result<()> { let unit = Arc::new(unit); - let vm = Vm::new(Arc::new(context.runtime()), unit); + let vm = Vm::new(Arc::new(context.runtime()?), unit); { let mut foo = External::default(); @@ -133,7 +133,7 @@ fn assign_ops_tuple() -> Result<()> { number.3 {op} {arg}; }} "#, op = stringify!($($op)*), arg = stringify!($arg)), - )); + ))?; let unit = prepare(&mut sources) .with_context(&context) @@ -141,7 +141,7 @@ fn assign_ops_tuple() -> Result<()> { let unit = Arc::new(unit); - let vm = Vm::new(Arc::new(context.runtime()), unit); + let vm = Vm::new(Arc::new(context.runtime()?), unit); { let mut foo = External::default(); @@ -205,7 +205,7 @@ fn ordering_struct() -> Result<()> { number {op} {arg} }} "#, op = stringify!($($op)*), arg = stringify!($arg)), - )); + ))?; let unit = prepare(&mut sources) .with_context(&context) @@ -213,7 +213,7 @@ fn ordering_struct() -> Result<()> { let unit = Arc::new(unit); - let vm = Vm::new(Arc::new(context.runtime()), unit); + let vm = Vm::new(Arc::new(context.runtime()?), unit); { let mut foo = External::default(); @@ -274,7 +274,7 @@ fn eq_struct() -> Result<()> { number {op} {arg} }} "#, op = stringify!($($op)*), arg = stringify!($arg)), - )); + ))?; let unit = prepare(&mut sources) .with_context(&context) @@ -282,7 +282,7 @@ fn eq_struct() -> Result<()> { let unit = Arc::new(unit); - let vm = Vm::new(Arc::new(context.runtime()), unit); + let vm = Vm::new(Arc::new(context.runtime()?), unit); { let mut foo = External::default(); diff --git a/crates/rune/src/tests/getter_setter.rs b/crates/rune/src/tests/getter_setter.rs index 4d6c10824..97fe2bf51 100644 --- a/crates/rune/src/tests/getter_setter.rs +++ b/crates/rune/src/tests/getter_setter.rs @@ -29,7 +29,7 @@ fn test_getter_setter() -> Result<()> { let unit = prepare(&mut sources).with_context(&context).build()?; - let mut vm = Vm::new(Arc::new(context.runtime()), Arc::new(unit)); + let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); let mut foo = Foo { number: 42, diff --git a/crates/rune/src/tests/macros.rs b/crates/rune/src/tests/macros.rs index 915df329a..6bdff671e 100644 --- a/crates/rune/src/tests/macros.rs +++ b/crates/rune/src/tests/macros.rs @@ -10,7 +10,7 @@ use crate::no_std::prelude::*; use crate::no_std::sync::Arc; #[test] -fn test_concat_idents() -> rune::Result<()> { +fn test_concat_idents() -> rune::support::Result<()> { #[rune::macro_] fn concat_idents( cx: &mut MacroContext<'_, '_, '_>, @@ -34,8 +34,8 @@ fn test_concat_idents() -> rune::Result<()> { p.eof()?; - let output = cx.ident(&output); - Ok(quote!(#output).into_token_stream(cx)) + let output = cx.ident(&output)?; + Ok(quote!(#output).into_token_stream(cx)?) } let mut m = Module::new(); @@ -44,7 +44,7 @@ fn test_concat_idents() -> rune::Result<()> { let mut context = Context::new(); context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { @@ -83,7 +83,7 @@ fn test_concat_idents() -> rune::Result<()> { } #[test] -fn test_rename() -> rune::Result<()> { +fn test_rename() -> rune::support::Result<()> { #[rune::attribute_macro] fn rename( cx: &mut MacroContext<'_, '_, '_>, @@ -97,7 +97,7 @@ fn test_rename() -> rune::Result<()> { fun.name = parser.parse_all::>()?.value; let mut tokens = TokenStream::new(); - fun.to_tokens(cx, &mut tokens); + fun.to_tokens(cx, &mut tokens)?; Ok(tokens) } @@ -107,7 +107,7 @@ fn test_rename() -> rune::Result<()> { let mut context = Context::new(); context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/crates/rune/src/tests/quote.rs b/crates/rune/src/tests/quote.rs index 6c96092aa..de9c75bf1 100644 --- a/crates/rune/src/tests/quote.rs +++ b/crates/rune/src/tests/quote.rs @@ -2,11 +2,11 @@ prelude!(); use ast::Kind::*; use ast::{CopySource, Delimiter, LitSource, NumberSource, StrSource}; -use macros::{quote, MacroContext}; +use macros::quote; macro_rules! assert_quote { ($cx:expr, [$($expected:pat),* $(,)?], $quote:expr) => { - let ts = $quote.into_token_stream($cx); + let ts = $quote.into_token_stream($cx).unwrap(); let mut it = ts.into_iter(); $( @@ -19,8 +19,8 @@ macro_rules! assert_quote { } #[test] -fn test_tokens() { - MacroContext::test(|cx| { +fn test_tokens() -> Result<()> { + macros::test(|cx| { assert_quote!(cx, [Amp], quote!(&)); assert_quote!(cx, [Abstract], quote!(abstract)); assert_quote!(cx, [AlignOf], quote!(alignof)); @@ -117,12 +117,15 @@ fn test_tokens() { assert_quote!(cx, [Virtual], quote!(virtual)); assert_quote!(cx, [While], quote!(while)); assert_quote!(cx, [Yield], quote!(yield)); - }); + Ok(()) + })?; + + Ok(()) } #[test] -fn test_synthetic() { - MacroContext::test(|cx| { +fn test_synthetic() -> Result<()> { + macros::test(|cx| { assert_quote!(cx, [Ident(LitSource::Synthetic(..))], quote!(hello)); assert_quote!(cx, [ByteStr(StrSource::Synthetic(..))], quote!(b"hello")); assert_quote!(cx, [Str(StrSource::Synthetic(..))], quote!("hello")); @@ -130,20 +133,26 @@ fn test_synthetic() { assert_quote!(cx, [Number(NumberSource::Synthetic(..))], quote!(42.0)); assert_quote!(cx, [Char(CopySource::Inline('a'))], quote!('a')); assert_quote!(cx, [Byte(CopySource::Inline(b'a'))], quote!(b'a')); - }); + Ok(()) + })?; + + Ok(()) } #[test] -fn test_interpolate() { - MacroContext::test(|cx| { +fn test_interpolate() -> Result<()> { + macros::test(|cx| { let outer = quote!(self struct enum); assert_quote!(cx, [SelfValue, Struct, Enum], quote!(#outer)); - }); + Ok(()) + })?; + + Ok(()) } #[test] -fn test_attribute() { - MacroContext::test(|cx| { +fn test_attribute() -> Result<()> { + macros::test(|cx| { assert_quote!( cx, [ @@ -154,12 +163,16 @@ fn test_attribute() { ], quote!(#[test]) ); - }); + + Ok(()) + })?; + + Ok(()) } #[test] -fn test_object() { - MacroContext::test(|cx| { +fn test_object() -> Result<()> { + macros::test(|cx| { assert_quote!( cx, [ @@ -172,5 +185,9 @@ fn test_object() { ], quote!(#{test: 42}) ); - }); + + Ok(()) + })?; + + Ok(()) } diff --git a/crates/rune/src/tests/range.rs b/crates/rune/src/tests/range.rs index ba7cdff33..139451670 100644 --- a/crates/rune/src/tests/range.rs +++ b/crates/rune/src/tests/range.rs @@ -129,15 +129,15 @@ fn test_range_non_eager_brace() { fn unsupported_compile_range() { assert_errors! { "pub fn main() { 'a'..= }", - span!(16, 22), Custom { message } => { - assert_eq!(message.as_ref(), "Unsupported range, you probably want `..` instead of `..=`") + span!(16, 22), Custom { error } => { + assert_eq!(error.to_string(), "Unsupported range, you probably want `..` instead of `..=`") } }; assert_errors! { "pub fn main() { ..= }", - span!(16, 19), Custom { message } => { - assert_eq!(message.as_ref(), "Unsupported range, you probably want `..` instead of `..=`") + span!(16, 19), Custom { error } => { + assert_eq!(error.to_string(), "Unsupported range, you probably want `..` instead of `..=`") } }; } diff --git a/crates/rune/src/tests/reference_error.rs b/crates/rune/src/tests/reference_error.rs index 181221b1b..cf8c3b265 100644 --- a/crates/rune/src/tests/reference_error.rs +++ b/crates/rune/src/tests/reference_error.rs @@ -29,7 +29,7 @@ fn test_reference_error() -> Result<()> { let unit = prepare(&mut sources).with_context(&context).build()?; - let mut vm = Vm::new(Arc::new(context.runtime()), Arc::new(unit)); + let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); let mut foo = Foo::default(); assert_eq!(foo.value, 0); diff --git a/crates/rune/src/tests/rename_type.rs b/crates/rune/src/tests/rename_type.rs index 5fecbaec6..d83fe340e 100644 --- a/crates/rune/src/tests/rename_type.rs +++ b/crates/rune/src/tests/rename_type.rs @@ -8,17 +8,19 @@ struct Foo {} struct Bar {} #[test] -fn test_rename() { +fn test_rename() -> Result<()> { let mut module = Module::new(); module.ty::().unwrap(); let e = module.ty::().unwrap_err(); match e { ContextError::ConflictingType { item, .. } => { - assert_eq!(item, ItemBuf::with_item(["Bar"])); + assert_eq!(item, ItemBuf::with_item(["Bar"])?); } actual => { panic!("Expected conflicting type but got: {:?}", actual); } } + + Ok(()) } diff --git a/crates/rune/src/tests/type_name_native.rs b/crates/rune/src/tests/type_name_native.rs index a794719c7..2a310cf53 100644 --- a/crates/rune/src/tests/type_name_native.rs +++ b/crates/rune/src/tests/type_name_native.rs @@ -16,7 +16,7 @@ impl NativeStruct { } fn make_native_module() -> Result { - let mut module = Module::with_crate("native_crate"); + let mut module = Module::with_crate("native_crate")?; module.ty::()?; module.function(["native_fn"], native_fn)?; module.associated_function("instance_fn", NativeStruct::instance_fn)?; diff --git a/crates/rune/src/tests/unit_constants.rs b/crates/rune/src/tests/unit_constants.rs index 76781dfdb..b7b4fdbf9 100644 --- a/crates/rune/src/tests/unit_constants.rs +++ b/crates/rune/src/tests/unit_constants.rs @@ -15,7 +15,7 @@ fn test_get_const() -> Result<()> { assert_eq!( unit.constant(Hash::type_hash(["LEET"])) .expect("successful lookup") - .clone() + .try_clone()? .into_value() .expect("could not allocate value") .into_integer() @@ -44,7 +44,7 @@ fn test_get_const_re_export() -> Result<()> { assert_eq!( unit.constant(Hash::type_hash(["LEET"])) .expect("successful lookup") - .clone() + .try_clone()? .into_value() .expect("could not allocate value") .into_integer() @@ -71,7 +71,7 @@ fn test_get_const_nested() -> Result<()> { assert_eq!( unit.constant(Hash::type_hash(["inner", "LEET"])) .expect("successful lookup") - .clone() + .try_clone()? .into_value() .expect("could not allocate value") .into_integer() diff --git a/crates/rune/src/worker.rs b/crates/rune/src/worker.rs index aa44a6bf7..346926159 100644 --- a/crates/rune/src/worker.rs +++ b/crates/rune/src/worker.rs @@ -1,10 +1,7 @@ //! Worker used by compiler. -use crate::no_std::prelude::*; - -use crate::no_std::collections::HashMap; -use crate::no_std::collections::VecDeque; - +use crate::alloc::prelude::*; +use crate::alloc::{Box, HashMap, Vec, VecDeque}; use crate::ast; use crate::ast::Span; use crate::compile::{self, ModId}; @@ -64,77 +61,71 @@ impl<'a, 'arena> Worker<'a, 'arena> { mod_item, mod_item_id, } => { - let item = self.q.pool.module_item(mod_item); - tracing::trace!("load file: {}", item); - - let Some(source) = self.q.sources.get(source_id) else { - self.q - .diagnostics - .internal(source_id, "Missing queued source by id"); - continue; - }; - - let root = match kind { - LoadFileKind::Root => source.path().map(ToOwned::to_owned), - LoadFileKind::Module { root } => root, - }; - - let items = Items::new(item, mod_item_id, self.q.gen); - - macro_rules! indexer { - () => { - Indexer { - q: self.q.borrow(), - root, - source_id, - items, - scopes: Scopes::default(), - item: IndexItem::new(mod_item), - nested_item: None, - macro_depth: 0, - loaded: Some(&mut self.loaded), - queue: Some(&mut self.queue), - } + let result = (|| { + let Some(source) = self.q.sources.get(source_id) else { + self.q + .diagnostics + .internal(source_id, "Missing queued source by id"); + return Ok(()); }; - } - if self.q.options.function_body { - let ast = match crate::parse::parse_all::( - source.as_str(), - source_id, - true, - ) { - Ok(ast) => ast, - Err(error) => { - self.q.diagnostics.error(source_id, error); - continue; + let item = self.q.pool.module_item(mod_item); + tracing::trace!("Load file: {}", item); + + let root = match kind { + LoadFileKind::Root => { + source.path().map(|p| p.try_to_owned()).transpose()? } + LoadFileKind::Module { root } => root, }; - let span = Span::new(0, source.len()); - let mut idx = indexer!(); - - if let Err(error) = index::empty_block_fn(&mut idx, ast, &span) { - idx.q.diagnostics.error(source_id, error); + let items = Items::new(item, mod_item_id, self.q.gen)?; + + macro_rules! indexer { + () => { + Indexer { + q: self.q.borrow(), + root, + source_id, + items, + scopes: Scopes::new()?, + item: IndexItem::new(mod_item), + nested_item: None, + macro_depth: 0, + loaded: Some(&mut self.loaded), + queue: Some(&mut self.queue), + } + }; } - } else { - let mut ast = match crate::parse::parse_all::( - source.as_str(), - source_id, - true, - ) { - Ok(ast) => ast, - Err(error) => { - self.q.diagnostics.error(source_id, error); - continue; - } - }; - let mut idx = indexer!(); + if self.q.options.function_body { + let ast = crate::parse::parse_all::( + source.as_str(), + source_id, + true, + )?; + + let span = Span::new(0, source.len()); + let mut idx = indexer!(); - if let Err(error) = index::file(&mut idx, &mut ast) { - idx.q.diagnostics.error(source_id, error); + index::empty_block_fn(&mut idx, ast, &span)?; + } else { + let mut ast = crate::parse::parse_all::( + source.as_str(), + source_id, + true, + )?; + + let mut idx = indexer!(); + + index::file(&mut idx, &mut ast)?; } + + Ok::<_, compile::Error>(()) + })(); + + if let Err(error) = result { + self.q.diagnostics.error(source_id, error); } } Task::ExpandImport(import) => { @@ -144,7 +135,8 @@ impl<'a, 'arena> Worker<'a, 'arena> { let queue = &mut self.queue; let result = import.process(&mut self.q, &mut |task| { - queue.push_back(task); + queue.try_push_back(task)?; + Ok(()) }); if let Err(error) = result { @@ -153,7 +145,14 @@ impl<'a, 'arena> Worker<'a, 'arena> { } Task::ExpandWildcardImport(wildcard_import) => { tracing::trace!("expand wildcard import"); - wildcard_imports.push(wildcard_import); + + let source_id = wildcard_import.location.source_id; + + if let Err(error) = wildcard_imports.try_push(wildcard_import) { + self.q + .diagnostics + .error(source_id, compile::Error::from(error)); + } } } } @@ -197,17 +196,20 @@ impl<'a, 'arena> Worker<'a, 'arena> { // TODO: this should not be necessary, since the item being // referenced should already have been inserted at this // point. - self.q.inner.items.insert(meta.item_meta.id, meta.item_meta); + self.q + .inner + .items + .try_insert(meta.item_meta.id, meta.item_meta)?; let item = self.q.pool.item(meta.item_meta.item); - let items = Items::new(item, meta.item_meta.id, self.q.gen); + let items = Items::new(item, meta.item_meta.id, self.q.gen)?; let mut idx = Indexer { q: self.q.borrow(), root: entry.root, source_id: entry.location.source_id, items, - scopes: Scopes::default(), + scopes: Scopes::new()?, item: IndexItem::with_impl_item(named.module, meta.item_meta.id), nested_item: entry.nested_item, macro_depth: entry.macro_depth, @@ -223,7 +225,7 @@ impl<'a, 'arena> Worker<'a, 'arena> { .unwrap_or_default(); for f in removed { - index::item_fn_immediate(&mut idx, *f.ast)?; + index::item_fn_immediate(&mut idx, Box::into_inner(f.ast))?; } Ok::<_, compile::Error>(()) diff --git a/crates/rune/src/worker/import.rs b/crates/rune/src/worker/import.rs index 4ac9c7c35..dd8d16bbd 100644 --- a/crates/rune/src/worker/import.rs +++ b/crates/rune/src/worker/import.rs @@ -1,8 +1,7 @@ use core::mem::take; -use crate::no_std::collections::VecDeque; -use crate::no_std::prelude::*; - +use crate::alloc::prelude::*; +use crate::alloc::{self, Box, VecDeque}; use crate::ast; use crate::ast::Spanned; use crate::compile::{self, DynLocation, ErrorKind, ItemBuf, Location, ModId, Visibility}; @@ -24,12 +23,12 @@ pub(crate) struct Import { impl Import { /// Lookup a local identifier in the current context and query. - fn lookup_local(&self, query: &Query<'_, '_>, local: &str) -> ItemBuf { - let item = query.pool.module_item(self.module).extended(local); + fn lookup_local(&self, query: &Query<'_, '_>, local: &str) -> alloc::Result { + let item = query.pool.module_item(self.module).extended(local)?; if let ImportKind::Local = self.kind { - if query.contains_prefix(&item) { - return item; + if query.contains_prefix(&item)? { + return Ok(item); } } @@ -37,14 +36,14 @@ impl Import { return ItemBuf::with_crate(local); } - item + Ok(item) } /// Process the import, populating the unit. pub(crate) fn process( mut self, q: &mut Query<'_, '_>, - add_task: &mut impl FnMut(Task), + add_task: &mut impl FnMut(Task) -> compile::Result<()>, ) -> compile::Result<()> { let (name, first, initial) = match self.kind { ImportKind::Global => { @@ -52,7 +51,7 @@ impl Import { Some(global) => match &self.ast.path.first { ast::ItemUseSegment::PathSegment(ast::PathSegment::Ident(ident)) => { let ident = ident.resolve(resolve_context!(q))?; - (ItemBuf::with_crate(ident), None, false) + (ItemBuf::with_crate(ident)?, None, false) } _ => { return Err(compile::Error::new( @@ -64,7 +63,7 @@ impl Import { // NB: defer non-local imports. _ => { self.kind = ImportKind::Local; - add_task(Task::ExpandImport(self)); + add_task(Task::ExpandImport(self))?; return Ok(()); } } @@ -74,7 +73,7 @@ impl Import { let mut queue = VecDeque::new(); - queue.push_back((&self.ast.path, name, first, initial)); + queue.try_push_back((&self.ast.path, name, first, initial))?; while let Some((path, mut name, first, mut initial)) = queue.pop_front() { tracing::trace!("process one"); @@ -99,11 +98,11 @@ impl Import { let ident = ident.resolve(resolve_context!(q))?; if !initial { - name.push(ident); + name.push(ident)?; continue; } - name = self.lookup_local(q, ident); + name = self.lookup_local(q, ident)?; } ast::PathSegment::SelfType(self_type) => { return Err(compile::Error::new( @@ -119,7 +118,7 @@ impl Import { )); } - name = q.pool.module_item(self.module).to_owned(); + name = q.pool.module_item(self.module).try_to_owned()?; } ast::PathSegment::Crate(crate_token) => { if !initial { @@ -133,10 +132,10 @@ impl Import { } ast::PathSegment::Super(super_token) => { if initial { - name = q.pool.module_item(self.module).to_owned(); + name = q.pool.module_item(self.module).try_to_owned()?; } - name.pop().ok_or_else(|| { + name.pop()?.ok_or_else(|| { compile::Error::new(super_token, ErrorKind::UnsupportedSuper) })?; } @@ -150,15 +149,15 @@ impl Import { ast::ItemUseSegment::Wildcard(star_token) => { let mut wildcard_import = WildcardImport { visibility: self.visibility, - from: self.item.clone(), - name: name.clone(), + from: self.item.try_clone()?, + name: name.try_clone()?, location: Location::new(self.source_id, star_token.span()), module: self.module, found: false, }; wildcard_import.process_global(q)?; - add_task(Task::ExpandWildcardImport(wildcard_import)); + add_task(Task::ExpandWildcardImport(wildcard_import))?; break Some(star_token.span()); } ast::ItemUseSegment::Group(group) => { @@ -170,7 +169,12 @@ impl Import { )); } - queue.push_back((path, name.clone(), Some(&path.first), initial)); + queue.try_push_back(( + path, + name.try_clone()?, + Some(&path.first), + initial, + ))?; } break Some(group.span()); @@ -201,7 +205,7 @@ impl Import { &DynLocation::new(self.source_id, path), self.module, self.visibility, - self.item.clone(), + self.item.try_clone()?, name, alias, false, diff --git a/crates/rune/src/worker/task.rs b/crates/rune/src/worker/task.rs index 6e108baca..5f712e03f 100644 --- a/crates/rune/src/worker/task.rs +++ b/crates/rune/src/worker/task.rs @@ -1,5 +1,4 @@ -use crate::no_std::path::PathBuf; - +use crate::alloc::path::PathBuf; use crate::compile::ModId; use crate::parse::NonZeroId; use crate::worker::{Import, WildcardImport}; diff --git a/crates/rune/src/worker/wildcard_import.rs b/crates/rune/src/worker/wildcard_import.rs index 1d395e411..f6eca5573 100644 --- a/crates/rune/src/worker/wildcard_import.rs +++ b/crates/rune/src/worker/wildcard_import.rs @@ -1,5 +1,5 @@ -use crate::no_std::prelude::*; - +use crate::alloc::prelude::*; +use crate::alloc::Vec; use crate::compile::{self, ErrorKind, IntoComponent, ItemBuf, Location, ModId, Visibility}; use crate::query::Query; @@ -14,15 +14,15 @@ pub(crate) struct WildcardImport { impl WildcardImport { pub(crate) fn process_global(&mut self, query: &mut Query<'_, '_>) -> compile::Result<()> { - if query.context.contains_prefix(&self.name) { - for c in query.context.iter_components(&self.name) { - let name = self.name.extended(c); + if query.context.contains_prefix(&self.name)? { + for c in query.context.iter_components(&self.name)? { + let name = self.name.extended(c)?; query.insert_import( &self.location, self.module, self.visibility, - self.from.clone(), + self.from.try_clone()?, name, None, true, @@ -37,20 +37,20 @@ impl WildcardImport { /// Process a local wildcard import. pub(crate) fn process_local(&mut self, query: &mut Query) -> compile::Result<()> { - if query.contains_prefix(&self.name) { + if query.contains_prefix(&self.name)? { let components = query - .iter_components(&self.name) + .iter_components(&self.name)? .map(|c| c.into_component()) - .collect::>(); + .try_collect::, _>>()??; for c in components { - let name = self.name.extended(c); + let name = self.name.extended(c)?; query.insert_import( &self.location, self.module, self.visibility, - self.from.clone(), + self.from.try_clone()?, name, None, true, @@ -64,7 +64,7 @@ impl WildcardImport { return Err(compile::Error::new( self.location, ErrorKind::MissingItem { - item: self.name.clone(), + item: self.name.try_clone()?, }, )); } diff --git a/crates/rune/src/workspace/build.rs b/crates/rune/src/workspace/build.rs index a490d4262..18c80263b 100644 --- a/crates/rune/src/workspace/build.rs +++ b/crates/rune/src/workspace/build.rs @@ -1,7 +1,7 @@ use core::fmt; use crate::Sources; -use crate::workspace::{SourceLoader, Diagnostics, FileSourceLoader}; +use crate::workspace::{SourceLoader, Diagnostics, FileSourceLoader, WorkspaceError}; use crate::workspace::manifest::{Loader, Manifest}; /// Failed to build workspace. @@ -79,7 +79,10 @@ impl<'a> Build<'a> { for id in self.sources.source_ids() { let mut loader = Loader::new(id, self.sources, diagnostics, source_loader, &mut manifest); - loader.load_manifest(); + + if let Err(error) = loader.load_manifest() { + diagnostics.fatal(id, WorkspaceError::from(error)); + } } if diagnostics.has_errors() { diff --git a/crates/rune/src/workspace/diagnostics.rs b/crates/rune/src/workspace/diagnostics.rs index f0d963a49..42b427201 100644 --- a/crates/rune/src/workspace/diagnostics.rs +++ b/crates/rune/src/workspace/diagnostics.rs @@ -1,6 +1,6 @@ use crate::no_std::prelude::*; -use crate::{SourceId}; +use crate::SourceId; use crate::workspace::WorkspaceError; /// A fatal diagnostic in a workspace. diff --git a/crates/rune/src/workspace/error.rs b/crates/rune/src/workspace/error.rs index 6ac24067d..3e5ddc0ff 100644 --- a/crates/rune/src/workspace/error.rs +++ b/crates/rune/src/workspace/error.rs @@ -1,18 +1,18 @@ use core::fmt; -use crate::no_std::prelude::*; +use std::path::Path; +use std::io; -use crate::no_std::path::Path; -use crate::no_std::io; - -use crate::{SourceId}; +use crate::alloc::{self, Box, String}; +use crate::SourceId; +use crate::compile::HasSpan; use crate::ast::{Span, Spanned}; /// An error raised when interacting with workspaces. #[derive(Debug)] pub struct WorkspaceError { span: Span, - kind: Box, + kind: rust_alloc::boxed::Box, } impl WorkspaceError { @@ -25,7 +25,7 @@ impl WorkspaceError { { Self { span: spanned.span(), - kind: Box::new(WorkspaceErrorKind::from(kind)), + kind: rust_alloc::boxed::Box::new(WorkspaceErrorKind::from(kind)), } } @@ -33,9 +33,9 @@ impl WorkspaceError { pub fn msg(spanned: S, message: M) -> Self where S: Spanned, - M: fmt::Display, + M: fmt::Display + fmt::Debug + Send + Sync + 'static, { - Self::new(spanned, WorkspaceErrorKind::Custom { message: message.to_string().into() }) + Self::new(spanned, WorkspaceErrorKind::Custom { error: anyhow::Error::msg(message) }) } } @@ -69,12 +69,22 @@ impl WorkspaceError { } } +impl From> for WorkspaceError +where + S: Spanned, + WorkspaceErrorKind: From, +{ + fn from(spanned: HasSpan) -> Self { + Self::new(spanned.span(), spanned.into_inner()) + } +} + /// A workspace error. #[derive(Debug)] #[allow(missing_docs)] #[non_exhaustive] pub(crate) enum WorkspaceErrorKind { - Custom { message: Box }, + Custom { error: anyhow::Error }, FileError { path: Box, error: io::Error, @@ -87,6 +97,7 @@ pub(crate) enum WorkspaceErrorKind { MissingManifestPath, ExpectedTable, UnsupportedKey { key: String }, + AllocError { error: alloc::Error }, } impl crate::no_std::error::Error for WorkspaceErrorKind { @@ -109,8 +120,8 @@ impl crate::no_std::error::Error for WorkspaceErrorKind { impl fmt::Display for WorkspaceErrorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - WorkspaceErrorKind::Custom { message } => { - write!(f, "{message}") + WorkspaceErrorKind::Custom { error } => { + error.fmt(f) } WorkspaceErrorKind::FileError { path, error } => write!( f, @@ -143,20 +154,33 @@ impl fmt::Display for WorkspaceErrorKind { f, "Key `{key}` not supported", ), + WorkspaceErrorKind::AllocError { error } => error.fmt(f), } } } impl From for WorkspaceErrorKind { #[allow(deprecated)] - fn from(source: toml::de::Error) -> Self { - WorkspaceErrorKind::Toml { error: source } + fn from(error: toml::de::Error) -> Self { + WorkspaceErrorKind::Toml { error } } } impl From for WorkspaceErrorKind { #[allow(deprecated)] - fn from(source: serde_hashkey::Error) -> Self { - WorkspaceErrorKind::Key { error: source } + fn from(error: serde_hashkey::Error) -> Self { + WorkspaceErrorKind::Key { error } } -} \ No newline at end of file +} + +impl From for WorkspaceError { + fn from(error: alloc::Error) -> Self { + WorkspaceError::new(Span::empty(), error) + } +} + +impl From for WorkspaceErrorKind { + fn from(error: alloc::Error) -> Self { + WorkspaceErrorKind::AllocError { error } + } +} diff --git a/crates/rune/src/workspace/manifest.rs b/crates/rune/src/workspace/manifest.rs index 573dd99e6..6d6fdb549 100644 --- a/crates/rune/src/workspace/manifest.rs +++ b/crates/rune/src/workspace/manifest.rs @@ -1,18 +1,19 @@ use std::fmt; use std::path::{PathBuf, Path}; -use std::{iter}; +use std::iter; use std::io; use std::fs; use std::ffi::OsStr; -use crate::no_std::prelude::*; - +use anyhow::Result; use relative_path::{RelativePathBuf, RelativePath}; use semver::Version; -use serde::de::{IntoDeserializer}; +use serde::de::IntoDeserializer; use serde::Deserialize; use serde_hashkey as key; +use crate::alloc::{self, Vec, String}; +use crate::alloc::prelude::*; use crate::{Sources, SourceId}; use crate::ast::{Span, Spanned}; use crate::workspace::{MANIFEST_FILE, WorkspaceErrorKind, Diagnostics, WorkspaceError, SourceLoader}; @@ -109,12 +110,12 @@ pub struct Manifest { } impl Manifest { - fn find_paths<'m>(&'m self, m: WorkspaceFilter<'_>, kind: FoundKind, auto_path: &Path, auto_find: fn(&Package) -> bool) -> io::Result>> { + fn find_paths<'m>(&'m self, m: WorkspaceFilter<'_>, kind: FoundKind, auto_path: &Path, auto_find: fn(&Package) -> bool) -> Result>> { let mut output = Vec::new(); for package in self.packages.iter() { for found in package.find_paths(m, kind, auto_path, auto_find)? { - output.push(FoundPackage { found, package }); + output.try_push(FoundPackage { found, package })?; } } @@ -122,32 +123,32 @@ impl Manifest { } /// Find every single entrypoint available. - pub fn find_all(&self, m: WorkspaceFilter<'_>) -> io::Result>> { + pub fn find_all(&self, m: WorkspaceFilter<'_>) -> Result>> { let mut output = Vec::new(); - output.extend(self.find_bins(m)?); - output.extend(self.find_tests(m)?); - output.extend(self.find_examples(m)?); - output.extend(self.find_benches(m)?); + output.try_extend(self.find_bins(m)?)?; + output.try_extend(self.find_tests(m)?)?; + output.try_extend(self.find_examples(m)?)?; + output.try_extend(self.find_benches(m)?)?; Ok(output) } /// Find all binaries matching the given name in the workspace. - pub fn find_bins(&self, m: WorkspaceFilter<'_>) -> io::Result>> { + pub fn find_bins(&self, m: WorkspaceFilter<'_>) -> Result>> { self.find_paths(m, FoundKind::Binary, Path::new(BIN), |p| p.auto_bins) } /// Find all tests associated with the given base name. - pub fn find_tests(&self, m: WorkspaceFilter<'_>) -> io::Result>> { + pub fn find_tests(&self, m: WorkspaceFilter<'_>) -> Result>> { self.find_paths(m, FoundKind::Test, Path::new(TESTS), |p| p.auto_tests) } /// Find all examples matching the given name in the workspace. - pub fn find_examples(&self, m: WorkspaceFilter<'_>) -> io::Result>> { + pub fn find_examples(&self, m: WorkspaceFilter<'_>) -> Result>> { self.find_paths(m, FoundKind::Example, Path::new(EXAMPLES), |p| p.auto_examples) } /// Find all benches matching the given name in the workspace. - pub fn find_benches(&self, m: WorkspaceFilter<'_>) -> io::Result>> { + pub fn find_benches(&self, m: WorkspaceFilter<'_>) -> Result>> { self.find_paths(m, FoundKind::Bench, Path::new(BENCHES), |p| p.auto_benches) } } @@ -173,7 +174,7 @@ pub struct Package { } impl Package { - fn find_paths(&self, m: WorkspaceFilter<'_>, kind: FoundKind, auto_path: &Path, auto_find: fn(&Package) -> bool) -> io::Result> { + fn find_paths(&self, m: WorkspaceFilter<'_>, kind: FoundKind, auto_path: &Path, auto_find: fn(&Package) -> bool) -> Result> { let mut output = Vec::new(); if let (Some(path), true) = (&self.root, auto_find(self)) { @@ -184,7 +185,7 @@ impl Package { let (path, name) = result?; if m.matches(&name) { - output.push(Found { kind, path, name }); + output.try_push(Found { kind, path, name })?; } } } @@ -193,32 +194,32 @@ impl Package { } /// Find every single entrypoint available. - pub fn find_all(&self, m: WorkspaceFilter<'_>) -> io::Result> { + pub fn find_all(&self, m: WorkspaceFilter<'_>) -> Result> { let mut output = Vec::new(); - output.extend(self.find_bins(m)?); - output.extend(self.find_tests(m)?); - output.extend(self.find_examples(m)?); - output.extend(self.find_benches(m)?); + output.try_extend(self.find_bins(m)?)?; + output.try_extend(self.find_tests(m)?)?; + output.try_extend(self.find_examples(m)?)?; + output.try_extend(self.find_benches(m)?)?; Ok(output) } /// Find all binaries matching the given name in the workspace. - pub fn find_bins(&self, m: WorkspaceFilter<'_>) -> io::Result> { + pub fn find_bins(&self, m: WorkspaceFilter<'_>) -> Result> { self.find_paths(m, FoundKind::Binary, Path::new(BIN), |p| p.auto_bins) } /// Find all tests associated with the given base name. - pub fn find_tests(&self, m: WorkspaceFilter<'_>) -> io::Result> { + pub fn find_tests(&self, m: WorkspaceFilter<'_>) -> Result> { self.find_paths(m, FoundKind::Test, Path::new(TESTS), |p| p.auto_tests) } /// Find all examples matching the given name in the workspace. - pub fn find_examples(&self, m: WorkspaceFilter<'_>) -> io::Result> { + pub fn find_examples(&self, m: WorkspaceFilter<'_>) -> Result> { self.find_paths(m, FoundKind::Example, Path::new(EXAMPLES), |p| p.auto_examples) } /// Find all benches matching the given name in the workspace. - pub fn find_benches(&self, m: WorkspaceFilter<'_>) -> io::Result> { + pub fn find_benches(&self, m: WorkspaceFilter<'_>) -> Result> { self.find_paths(m, FoundKind::Bench, Path::new(BENCHES), |p| p.auto_benches) } } @@ -245,10 +246,10 @@ impl<'a> Loader<'a> { } /// Load a manifest. - pub(crate) fn load_manifest(&mut self) { + pub(crate) fn load_manifest(&mut self) -> alloc::Result<()> { let Some(source) = self.sources.get(self.id) else { self.fatal(WorkspaceError::new(Span::empty(), WorkspaceErrorKind::MissingSourceId { source_id: self.id })); - return; + return Ok(()); }; let value: SpannedValue = match toml::from_str(source.as_str()) { @@ -260,21 +261,21 @@ impl<'a> Loader<'a> { }; self.fatal(WorkspaceError::new(span, e)); - return; + return Ok(()); } }; - let root = source.path().and_then(|p| Some(p.parent()?.to_owned())); + let root = source.path().and_then(|p| p.parent().map(TryToOwned::try_to_owned)).transpose()?; let root = root.as_deref(); let Some((mut table, _)) = self.ensure_table(value) else { - return; + return Ok(()); }; // If manifest is a package, add it here. if let Some((package, span)) = table.remove("package").and_then(|value| self.ensure_table(value)) { - if let Some(package) = self.load_package(package, span, root) { - self.manifest.packages.push(package); + if let Some(package) = self.load_package(package, span, root)? { + self.manifest.packages.try_push(package)?; } } @@ -282,9 +283,9 @@ impl<'a> Loader<'a> { if let Some((mut table, span)) = table.remove("workspace").and_then(|value| self.ensure_table(value)) { match &root { Some(root) => { - if let Some(members) = self.load_members(&mut table, root) { + if let Some(members) = self.load_members(&mut table, root)? { for (span, path) in members { - self.load_member(span, &path); + self.load_member(span, &path)?; } } }, @@ -293,19 +294,23 @@ impl<'a> Loader<'a> { } } - self.ensure_empty(table); + self.ensure_empty(table)?; } - self.ensure_empty(table); + self.ensure_empty(table)?; + Ok(()) } /// Load members from the given workspace configuration. - fn load_members(&mut self, table: &mut Table, root: &Path) -> Option> { + fn load_members(&mut self, table: &mut Table, root: &Path) -> alloc::Result>> { let Some(members) = table.remove("members") else { - return None; + return Ok(None); + }; + + let Some((members, _)) = self.ensure_array(members) else { + return Ok(None); }; - let (members, _) = self.ensure_array(members)?; let mut output = Vec::new(); for value in members { @@ -313,7 +318,7 @@ impl<'a> Loader<'a> { match deserialize::(value) { Ok(member) => { - self.glob_relative_path(&mut output, span, &member, root); + self.glob_relative_path(&mut output, span, &member, root)?; } Err(error) => { self.fatal(error); @@ -321,18 +326,18 @@ impl<'a> Loader<'a> { }; } - Some(output) + Ok(Some(output)) } /// Glob a relative path. /// /// Currently only supports expanding `*` and required interacting with the /// filesystem. - fn glob_relative_path(&mut self, output: &mut Vec<(Span, PathBuf)>, span: Span, member: &RelativePath, root: &Path) { + fn glob_relative_path(&mut self, output: &mut Vec<(Span, PathBuf)>, span: Span, member: &RelativePath, root: &Path) -> alloc::Result<()> { let glob = crate::workspace::glob::Glob::new(root, member); for m in glob.matcher() { - let Some(mut path) = self.source_error(span, root, m) else { + let Some(mut path) = self.source_error(span, root, m)? else { continue; }; @@ -342,64 +347,73 @@ impl<'a> Loader<'a> { continue; } - output.push((span, path)); + output.try_push((span, path))?; } + + Ok(()) } /// Helper to convert an [io::Error] into a [WorkspaceErrorKind::SourceError]. - fn source_error(&mut self, span: Span, path: &Path, result: io::Result) -> Option { - match result { + fn source_error(&mut self, span: Span, path: &Path, result: io::Result) -> alloc::Result> { + Ok(match result { Ok(result) => Some(result), Err(error) => { self.fatal(WorkspaceError::new(span, WorkspaceErrorKind::FileError { - path: path.into(), + path: path.try_into()?, error, })); None } - } + }) } /// Try to load the given path as a member in the current manifest. - fn load_member(&mut self, span: Span, path: &Path) { + fn load_member(&mut self, span: Span, path: &Path) -> alloc::Result<()> { let source = match self.source_loader.load(span, path) { Ok(source) => source, Err(error) => { self.fatal(error); - return; + return Ok(()); } }; - let id = self.sources.insert(source); + let id = self.sources.insert(source)?; let old = std::mem::replace(&mut self.id, id); - self.load_manifest(); + self.load_manifest()?; self.id = old; + Ok(()) } /// Load a package from a value. - fn load_package(&mut self, mut table: Table, span: Span, root: Option<&Path>) -> Option { + fn load_package(&mut self, mut table: Table, span: Span, root: Option<&Path>) -> alloc::Result> { let name = self.field(&mut table, span, "name"); let version = self.field(&mut table, span, "version"); - self.ensure_empty(table); + self.ensure_empty(table)?; - Some(Package { - name: name?, - version: version?, + let (Some(name), Some(version)) = (name, version) else { + return Ok(None); + }; + + Ok(Some(Package { + name, + version, root: root.map(|p| p.into()), auto_bins: true, auto_tests: true, auto_examples: true, auto_benches: true, - }) + })) } /// Ensure that a table is empty and mark any additional elements as erroneous. - fn ensure_empty(&mut self, table: Table) { + fn ensure_empty(&mut self, table: Table) -> alloc::Result<()> { for (key, _) in table { let span = Spanned::span(&key); - self.fatal(WorkspaceError::new(span, WorkspaceErrorKind::UnsupportedKey { key: key.get_ref().clone() })); + self.fatal(WorkspaceError::new(span, WorkspaceErrorKind::UnsupportedKey { key: key.get_ref().as_str().try_into()? })); } + + Ok(()) } /// Ensure that value is a table. @@ -466,11 +480,11 @@ fn deserialize(value: SpannedValue) -> Result where T: for } /// Find all rune files in the given path. -fn find_rune_files(path: &Path) -> io::Result>> { +fn find_rune_files(path: &Path) -> Result>> { let mut dir = match fs::read_dir(path) { Ok(dir) => Some(dir), Err(e) if e.kind() == io::ErrorKind::NotFound => None, - Err(e) => return Err(e), + Err(e) => return Err(e.into()), }; Ok(iter::from_fn(move || { @@ -479,12 +493,12 @@ fn find_rune_files(path: &Path) -> io::Result e, - Err(err) => return Some(Err(err)), + Err(err) => return Some(Err(err.into())), }; let m = match e.metadata() { Ok(m) => m, - Err(err) => return Some(Err(err)), + Err(err) => return Some(Err(err.into())), }; if !m.is_file() { @@ -501,7 +515,11 @@ fn find_rune_files(path: &Path) -> io::Result name, + Err(error) => return Some(Err(error.into())), + }; + return Some(Ok((path, name))); } })) diff --git a/crates/rune/src/workspace/source_loader.rs b/crates/rune/src/workspace/source_loader.rs index 4236e6bc1..22d18441b 100644 --- a/crates/rune/src/workspace/source_loader.rs +++ b/crates/rune/src/workspace/source_loader.rs @@ -3,6 +3,7 @@ use std::path::Path; use crate::ast::Span; use crate::Source; use crate::workspace::WorkspaceError; +use crate::compile::WithSpan; use super::WorkspaceErrorKind; @@ -30,7 +31,7 @@ impl SourceLoader for FileSourceLoader { Err(error) => Err(WorkspaceError::new( span, WorkspaceErrorKind::FileError { - path: path.into(), + path: path.try_into().with_span(span)?, error, }, )), diff --git a/editors/code/README.md b/editors/code/README.md index 4527a305a..0b88dad7d 100644 --- a/editors/code/README.md +++ b/editors/code/README.md @@ -78,9 +78,9 @@ use rune::termcolor::{ColorChoice, StandardStream}; use std::sync::Arc; #[tokio::main] -async fn main() -> rune::Result<()> { +async fn main() -> rune::support::Result<()> { let context = Context::with_default_modules()?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = Sources::new(); sources.insert(Source::new( diff --git a/examples/examples/checked_add_assign.rs b/examples/examples/checked_add_assign.rs index a92c62ce1..d5641cbce 100644 --- a/examples/examples/checked_add_assign.rs +++ b/examples/examples/checked_add_assign.rs @@ -1,6 +1,7 @@ use rune::runtime::{VmError, VmResult}; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Any, ContextError, Diagnostics, Module, Vm}; + use std::sync::Arc; #[derive(Any)] @@ -17,12 +18,12 @@ impl External { } } -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/concat_idents.rs b/examples/examples/concat_idents.rs index 4b8315d19..03628dfc7 100644 --- a/examples/examples/concat_idents.rs +++ b/examples/examples/concat_idents.rs @@ -4,6 +4,7 @@ use rune::macros::{quote, MacroContext, TokenStream}; use rune::parse::Parser; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Context, Diagnostics, Module, Vm, T}; + use std::sync::Arc; #[rune::macro_] @@ -29,18 +30,18 @@ fn concat_idents( p.eof()?; - let output = cx.ident(&output); - Ok(quote!(#output).into_token_stream(cx)) + let output = cx.ident(&output)?; + Ok(quote!(#output).into_token_stream(cx)?) } -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let mut m = Module::new(); m.macro_meta(concat_idents)?; let mut context = Context::new(); context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/custom_instance_fn.rs b/examples/examples/custom_instance_fn.rs index 83ba1bc8f..ec26a2fc2 100644 --- a/examples/examples/custom_instance_fn.rs +++ b/examples/examples/custom_instance_fn.rs @@ -1,5 +1,6 @@ use rune::termcolor::{ColorChoice, StandardStream}; use rune::{ContextError, Diagnostics, Module, Vm}; + use std::sync::Arc; #[rune::function(instance)] @@ -8,12 +9,12 @@ fn divide_by_three(value: i64) -> i64 { } #[tokio::main] -async fn main() -> rune::Result<()> { +async fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources!(entry => { pub fn main(number) { @@ -44,7 +45,7 @@ async fn main() -> rune::Result<()> { } fn module() -> Result { - let mut m = Module::with_item(["mymodule"]); + let mut m = Module::with_item(["mymodule"])?; m.function_meta(divide_by_three)?; Ok(m) } diff --git a/examples/examples/custom_mul.rs b/examples/examples/custom_mul.rs index ba9898f80..5bfa125cf 100644 --- a/examples/examples/custom_mul.rs +++ b/examples/examples/custom_mul.rs @@ -3,6 +3,7 @@ use rune::runtime::Protocol; use rune::{Any, ContextError, Diagnostics, Module, Vm}; + use std::sync::Arc; #[derive(Debug, Default, Any)] @@ -18,13 +19,13 @@ impl Foo { } } -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { @@ -50,7 +51,7 @@ fn main() -> rune::Result<()> { } fn module() -> Result { - let mut m = Module::with_item(["module"]); + let mut m = Module::with_item(["module"])?; m.ty::()?; m.associated_function(Protocol::MUL, Foo::mul)?; Ok(m) diff --git a/examples/examples/external_enum.rs b/examples/examples/external_enum.rs index 3f34542dd..87093bc42 100644 --- a/examples/examples/external_enum.rs +++ b/examples/examples/external_enum.rs @@ -1,9 +1,9 @@ -use std::sync::Arc; - use rune::runtime::Vm; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Any, ContextError, Diagnostics, Module}; +use std::sync::Arc; + #[derive(Debug, Any, PartialEq, Eq)] enum External { #[rune(constructor)] @@ -21,12 +21,12 @@ enum External { Output(#[rune(get)] u32), } -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/external_struct.rs b/examples/examples/external_struct.rs index 045a6ec1d..a346af214 100644 --- a/examples/examples/external_struct.rs +++ b/examples/examples/external_struct.rs @@ -1,9 +1,9 @@ -use std::sync::Arc; - use rune::runtime::Vm; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Any, ContextError, Diagnostics, Module}; +use std::sync::Arc; + #[derive(Default, Debug, Any, PartialEq, Eq)] struct Request { #[rune(get, set)] @@ -19,12 +19,12 @@ struct Response { body: String, } -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/function_hash.rs b/examples/examples/function_hash.rs index 5c2b44891..8e91b08ae 100644 --- a/examples/examples/function_hash.rs +++ b/examples/examples/function_hash.rs @@ -1,7 +1,8 @@ use rune::compile::ItemBuf; use rune::Hash; -fn main() { - println!("{}", Hash::type_hash(&ItemBuf::with_item(["Foo", "new"]))); +fn main() -> rune::support::Result<()> { + println!("{}", Hash::type_hash(&ItemBuf::with_item(["Foo", "new"])?)); println!("{}", Hash::type_hash(["Foo", "new"])); + Ok(()) } diff --git a/examples/examples/minimal.rs b/examples/examples/minimal.rs index 048f42a1c..c2626d40e 100644 --- a/examples/examples/minimal.rs +++ b/examples/examples/minimal.rs @@ -1,8 +1,9 @@ use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Diagnostics, Vm}; + use std::sync::Arc; -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let context = rune_modules::default_context()?; let mut sources = rune::sources!( @@ -27,7 +28,7 @@ fn main() -> rune::Result<()> { let unit = result?; - let mut vm = Vm::new(Arc::new(context.runtime()), Arc::new(unit)); + let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); let output = vm.execute(["main"], (33i64,))?.complete().into_result()?; let output: i64 = rune::from_value(output)?; diff --git a/examples/examples/native_function.rs b/examples/examples/native_function.rs index 6060627f1..4e9c0608c 100644 --- a/examples/examples/native_function.rs +++ b/examples/examples/native_function.rs @@ -1,14 +1,15 @@ use rune::termcolor::{ColorChoice, StandardStream}; use rune::{ContextError, Diagnostics, Module, Vm}; + use std::sync::Arc; -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/object.rs b/examples/examples/object.rs index c7e54537d..1df4e1dbd 100644 --- a/examples/examples/object.rs +++ b/examples/examples/object.rs @@ -2,11 +2,12 @@ use rune::alloc; use rune::runtime::Object; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Diagnostics, Value, Vm}; + use std::sync::Arc; -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let context = rune_modules::default_context()?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/parsing_in_macro.rs b/examples/examples/parsing_in_macro.rs index 5da3f57aa..8f1ecdad2 100644 --- a/examples/examples/parsing_in_macro.rs +++ b/examples/examples/parsing_in_macro.rs @@ -3,14 +3,15 @@ use rune::parse::Parser; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{ast, ContextError}; use rune::{Diagnostics, Module, Vm}; + use std::sync::Arc; -pub fn main() -> rune::Result<()> { +pub fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { @@ -50,20 +51,20 @@ fn module() -> Result { let string = "1 + 2 + 13 * 3"; m.macro_(["string_as_code"], move |cx, _| { - let id = cx.insert_source("string_as_code", string); + let id = cx.insert_source("string_as_code", string)?; let expr = cx.parse_source::(id)?; - Ok(quote!(#expr).into_token_stream(cx)) + Ok(quote!(#expr).into_token_stream(cx)?) })?; m.macro_(["string_as_code_from_arg"], |cx, stream| { let mut p = Parser::from_token_stream(stream, cx.input_span()); let s = p.parse_all::()?; - let s = cx.resolve(s)?.into_owned(); - let id = cx.insert_source("string_as_code_from_arg", &s); + let s = cx.resolve(s)?.try_into_owned()?; + let id = cx.insert_source("string_as_code_from_arg", &s)?; let expr = cx.parse_source::(id)?; - Ok(quote!(#expr).into_token_stream(cx)) + Ok(quote!(#expr).into_token_stream(cx)?) })?; Ok(m) diff --git a/examples/examples/proxy.rs b/examples/examples/proxy.rs index a94636864..84ef60dde 100644 --- a/examples/examples/proxy.rs +++ b/examples/examples/proxy.rs @@ -2,6 +2,7 @@ use rune::alloc; use rune::runtime::{Mut, Ref}; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Any, Context, Diagnostics, FromValue, Vm}; + use std::sync::Arc; #[derive(Any, Debug, Default)] @@ -16,7 +17,7 @@ struct Proxy { my_bytes: Ref, } -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let context = Context::with_default_modules()?; let mut sources = rune::sources! { @@ -41,7 +42,7 @@ fn main() -> rune::Result<()> { let unit = result?; - let mut vm = Vm::new(Arc::new(context.runtime()), Arc::new(unit)); + let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); let input = MyBytes { bytes: vec![77, 77, 77, 77], diff --git a/examples/examples/references.rs b/examples/examples/references.rs index 36e2b9caa..0f2223592 100644 --- a/examples/examples/references.rs +++ b/examples/examples/references.rs @@ -1,6 +1,7 @@ use rune::runtime::Protocol; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Any, Diagnostics, Module, Vm}; + use std::sync::Arc; #[derive(Debug, Default, Any)] @@ -15,7 +16,7 @@ impl Foo { } #[allow(clippy::disallowed_names)] -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let mut module = Module::new(); module.ty::()?; module.associated_function(Protocol::ADD_ASSIGN, Foo::add_assign)?; @@ -23,7 +24,7 @@ fn main() -> rune::Result<()> { let mut context = rune_modules::default_context()?; context.install(module)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/rune_function.rs b/examples/examples/rune_function.rs index 49feb89f6..6d9b720e6 100644 --- a/examples/examples/rune_function.rs +++ b/examples/examples/rune_function.rs @@ -1,11 +1,12 @@ use rune::runtime::Function; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Diagnostics, Vm}; + use std::sync::Arc; -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let context = rune_modules::default_context()?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/rune_function_macro.rs b/examples/examples/rune_function_macro.rs index 872333dba..c7ee2825d 100644 --- a/examples/examples/rune_function_macro.rs +++ b/examples/examples/rune_function_macro.rs @@ -1,16 +1,16 @@ -use std::sync::Arc; - use rune::termcolor::{ColorChoice, StandardStream}; use rune::Any; use rune::{ContextError, Diagnostics, Module, Vm}; -fn main() -> rune::Result<()> { +use std::sync::Arc; + +fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/simple_external.rs b/examples/examples/simple_external.rs index e4e2a4365..645362e89 100644 --- a/examples/examples/simple_external.rs +++ b/examples/examples/simple_external.rs @@ -1,9 +1,9 @@ -use std::sync::Arc; - use rune::runtime::Vm; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Any, ContextError, Diagnostics, Module}; +use std::sync::Arc; + #[derive(Debug, Any)] struct External { value: u32, @@ -15,12 +15,12 @@ pub fn module() -> Result { Ok(module) } -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/tokio_spawn.rs b/examples/examples/tokio_spawn.rs index da737d36b..34ca8ebfb 100644 --- a/examples/examples/tokio_spawn.rs +++ b/examples/examples/tokio_spawn.rs @@ -1,12 +1,13 @@ -use rune::alloc::TryClone; +use rune::alloc::prelude::*; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Diagnostics, Vm}; + use std::sync::Arc; #[tokio::main] -async fn main() -> rune::Result<()> { +async fn main() -> rune::support::Result<()> { let context = rune_modules::default_context()?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/tuple.rs b/examples/examples/tuple.rs index 6f688003b..62546fd02 100644 --- a/examples/examples/tuple.rs +++ b/examples/examples/tuple.rs @@ -1,10 +1,11 @@ use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Diagnostics, Vm}; + use std::sync::Arc; -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let context = rune_modules::default_context()?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/vec_args.rs b/examples/examples/vec_args.rs index 8e6289cb7..c7ddf76b1 100644 --- a/examples/examples/vec_args.rs +++ b/examples/examples/vec_args.rs @@ -1,16 +1,16 @@ -use std::sync::Arc; - use rune::alloc::Vec; use rune::runtime::{Function, VmResult}; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{ContextError, Diagnostics, Module, Value, Vm}; -fn main() -> rune::Result<()> { +use std::sync::Arc; + +fn main() -> rune::support::Result<()> { let m = module()?; let mut context = rune_modules::default_context()?; context.install(m)?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { @@ -47,7 +47,7 @@ fn main() -> rune::Result<()> { } fn module() -> Result { - let mut m = Module::with_item(["mymodule"]); + let mut m = Module::with_item(["mymodule"])?; m.function( ["pass_along"], diff --git a/examples/examples/vec_tuple.rs b/examples/examples/vec_tuple.rs index e7e08fd38..5cf21c631 100644 --- a/examples/examples/vec_tuple.rs +++ b/examples/examples/vec_tuple.rs @@ -1,11 +1,12 @@ use rune::runtime::VecTuple; use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Diagnostics, Vm}; + use std::sync::Arc; -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let context = rune_modules::default_context()?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/examples/examples/vector.rs b/examples/examples/vector.rs index 962d9d2c0..abeae2ca5 100644 --- a/examples/examples/vector.rs +++ b/examples/examples/vector.rs @@ -1,10 +1,11 @@ use rune::termcolor::{ColorChoice, StandardStream}; use rune::{Diagnostics, Vm}; + use std::sync::Arc; -fn main() -> rune::Result<()> { +fn main() -> rune::support::Result<()> { let context = rune_modules::default_context()?; - let runtime = Arc::new(context.runtime()); + let runtime = Arc::new(context.runtime()?); let mut sources = rune::sources! { entry => { diff --git a/no-std-examples/.gitignore b/no-std-examples/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/no-std-examples/.gitignore @@ -0,0 +1 @@ +target diff --git a/no-std-examples/Cargo.lock b/no-std-examples/Cargo.lock new file mode 100644 index 000000000..1520fb398 --- /dev/null +++ b/no-std-examples/Cargo.lock @@ -0,0 +1,484 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "libc" +version = "0.2.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "musli" +version = "0.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c21124dd24833900879114414b877f2136f4b7b7a3b49756ecc5c36eca332bb" +dependencies = [ + "musli-macros", +] + +[[package]] +name = "musli-common" +version = "0.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "178446623aa62978aa0f894b2081bc11ea77c2119ccfe35be428ab9ddb495dfc" +dependencies = [ + "musli", +] + +[[package]] +name = "musli-macros" +version = "0.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1ab0e4ac2721bc4fa3528a6a2640c1c30c36c820f8c85159252fbf6c2fac24" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "musli-storage" +version = "0.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2fc1f80b166f611c462e1344220e9b3a9ad37c885e43039d5d2e6887445937c" +dependencies = [ + "musli", + "musli-common", +] + +[[package]] +name = "no-std-examples" +version = "0.0.0" +dependencies = [ + "critical-section", + "rune", + "wee_alloc", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +dependencies = [ + "atomic-polyfill", + "critical-section", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rune" +version = "0.12.3" +dependencies = [ + "anyhow", + "futures-core", + "futures-util", + "itoa", + "musli", + "musli-storage", + "num", + "once_cell", + "pin-project", + "rune-alloc", + "rune-core", + "rune-macros", + "ryu", + "serde", + "slab", + "tracing", +] + +[[package]] +name = "rune-alloc" +version = "0.12.3" +dependencies = [ + "ahash", + "pin-project", + "rune-alloc-macros", + "serde", +] + +[[package]] +name = "rune-alloc-macros" +version = "0.12.3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "rune-core" +version = "0.12.3" +dependencies = [ + "byteorder", + "musli", + "rune-alloc", + "serde", + "twox-hash", +] + +[[package]] +name = "rune-macros" +version = "0.12.3" +dependencies = [ + "proc-macro2", + "quote", + "rune-core", + "syn", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "2.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if 1.0.0", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/no-std-examples/Cargo.toml b/no-std-examples/Cargo.toml index a188dab40..bd5d22337 100644 --- a/no-std-examples/Cargo.toml +++ b/no-std-examples/Cargo.toml @@ -11,3 +11,16 @@ std = ["rune/std"] [dependencies] rune = { path = "../crates/rune", default-features = false, features = ["alloc"] } wee_alloc = "0.4.5" +# Pull in your own critical-section implementation. +# See: https://github.com/rust-embedded/critical-section/tree/main#usage-in-no-std-binaries +critical-section = { version = "1.1.2", default-features = false } + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" + +[profile.unix] +lto = true +inherits = "dev" diff --git a/no-std-examples/examples/no_std_minimal.rs b/no-std-examples/examples/no_std_minimal.rs index 0dbfd4cc2..213b74d7e 100644 --- a/no-std-examples/examples/no_std_minimal.rs +++ b/no-std-examples/examples/no_std_minimal.rs @@ -1,5 +1,6 @@ #![no_std] #![feature(alloc_error_handler, start, core_intrinsics, lang_items, link_cfg)] +#![allow(internal_features)] extern crate alloc; @@ -17,7 +18,7 @@ fn err_handler(_: core::alloc::Layout) -> ! { #[panic_handler] #[lang = "panic_impl"] -extern "C" fn rust_begin_panic(_: &core::panic::PanicInfo) -> ! { +fn rust_begin_panic(_: &core::panic::PanicInfo) -> ! { core::intrinsics::abort(); } @@ -31,14 +32,56 @@ use rune::no_std::RawEnv; use rune::{Diagnostics, Vm}; static mut BUDGET: usize = usize::MAX; +static mut MEMORY: usize = usize::MAX; static mut RAW_ENV: RawEnv = RawEnv::null(); /// Necessary hook to abort the current process. #[no_mangle] -extern "C" fn __rune_abort() -> ! { +extern "C" fn __rune_alloc_abort() -> ! { core::intrinsics::abort() } +#[no_mangle] +extern "C" fn __rune_alloc_memory_take(amount: usize) -> bool { + unsafe { + if MEMORY == usize::MAX { + return true; + } + + if MEMORY >= amount { + MEMORY -= amount; + return true; + } + + return false; + } +} + +/// Release the given amount of memory to the current budget. +#[no_mangle] +extern "C" fn __rune_alloc_memory_release(amount: usize) { + unsafe { + if MEMORY == usize::MAX { + return; + } + + MEMORY = MEMORY.saturating_add(amount); + } +} + +/// Get the remaining memory budget for the current thread. +#[no_mangle] +extern "C" fn __rune_alloc_memory_get() -> usize { + unsafe { MEMORY } +} + +/// Replace the memory budget for the current thread and return the one which +/// was previously set. +#[no_mangle] +extern "C" fn __rune_alloc_memory_replace(value: usize) -> usize { + unsafe { replace(&mut MEMORY, value) } +} + #[no_mangle] extern "C" fn __rune_budget_take() -> bool { // SAFETY: this is only ever executed in a singlethreaded environment. @@ -76,6 +119,20 @@ extern "C" fn __rune_env_replace(env: RawEnv) -> RawEnv { unsafe { replace(&mut RAW_ENV, env) } } +use critical_section::RawRestoreState; + +struct MyCriticalSection; + +critical_section::set_impl!(MyCriticalSection); + +// SAFETY: In this instance, we might assume that the application is +// single-threaded. So no critical sections are used in practice. Therefore a +// dummy implementation is used. +unsafe impl critical_section::Impl for MyCriticalSection { + unsafe fn acquire() -> RawRestoreState {} + unsafe fn release(_: RawRestoreState) {} +} + #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { match inner_main() { @@ -84,7 +141,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { } } -fn inner_main() -> rune::Result { +fn inner_main() -> rune::support::Result { let context = rune::Context::with_default_modules()?; let mut sources = rune::sources!( @@ -104,8 +161,8 @@ fn inner_main() -> rune::Result { let unit = result?; - let mut vm = Vm::new(Arc::new(context.runtime()), Arc::new(unit)); + let mut vm = Vm::new(Arc::new(context.runtime()?), Arc::new(unit)); let output = vm.execute(["main"], (33i64,))?.complete().into_result()?; let output: i32 = rune::from_value(output)?; - Ok(output) + Ok((output != 43).into()) } diff --git a/tools/generate/Cargo.toml b/tools/generate/Cargo.toml index f658ea87c..a9567d07d 100644 --- a/tools/generate/Cargo.toml +++ b/tools/generate/Cargo.toml @@ -8,5 +8,5 @@ publish = false [dependencies] serde = { version = "1.0.163", features = ["derive"] } serde_yaml = "0.9.21" -genco = "0.17.5" +genco = "0.17.6" anyhow = "1.0.71" diff --git a/tools/generate/src/main.rs b/tools/generate/src/main.rs index e6cb3a407..e034114c6 100644 --- a/tools/generate/src/main.rs +++ b/tools/generate/src/main.rs @@ -137,16 +137,20 @@ fn main() -> Result<()> { let to_tokens = &rust::import("crate::macros", "ToTokens"); let token = &rust::import("crate::ast", "Token"); let token_stream = &rust::import("crate::macros", "TokenStream"); + let try_clone = &rust::import("crate::alloc::clone", "TryClone"); + let alloc = &rust::import("crate", "alloc"); write_tokens( Path::new("crates/rune/src/ast/generated.rs"), genco::quote! { + use crate as rune; $(format!("/// This file has been generated from `{}`", asset.display())) $("/// DO NOT modify by hand!") $(for t in &non_syntax join($['\n']) => $(format!("/// {}", t.doc())) - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + #[derive(Debug, $try_clone, Clone, Copy, PartialEq, Eq, Hash)] + #[try_clone(copy)] #[non_exhaustive] pub struct $(t.variant()) { $("/// Associated span.") @@ -183,11 +187,11 @@ fn main() -> Result<()> { } impl $to_tokens for $(t.variant()) { - fn to_tokens(&self, _: &mut $macro_context<'_, '_, '_>, stream: &mut $token_stream) { + fn to_tokens(&self, _: &mut $macro_context<'_, '_, '_>, stream: &mut $token_stream) -> $alloc::Result<()> { stream.push($token { span: self.span, kind: $kind::$(t.variant()), - }); + }) } } ) @@ -261,7 +265,7 @@ fn main() -> Result<()> { } $("/// The kind of the token.") - #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[derive(Debug, $try_clone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Kind { $("/// En end-of-file marker.") Eof, @@ -331,11 +335,11 @@ fn main() -> Result<()> { } impl $to_tokens for Kind { - fn to_tokens(&self, context: &mut $macro_context<'_, '_, '_>, stream: &mut $token_stream) { + fn to_tokens(&self, context: &mut $macro_context<'_, '_, '_>, stream: &mut $token_stream) -> $alloc::Result<()> { stream.push($token { kind: *self, span: context.macro_span(), - }); + }) } }