From ecaff7c868e6e04b76625a77f37bbe23e0421f29 Mon Sep 17 00:00:00 2001 From: Sandor Molnar Date: Mon, 8 Apr 2024 19:56:29 +0300 Subject: [PATCH] Backed out 5 changesets (bug 1890092, bug 1888683) for causing build bustages & crashes CLOSED TREE Backed out changeset d43df75c14de (bug 1888683) Backed out changeset b4267327c7dd (bug 1888683) Backed out changeset 11892428e2dc (bug 1890092) Backed out changeset 42598e432246 (bug 1888683) Backed out changeset 372016bf3614 (bug 1888683) --- .cargo/config.toml.in | 8 +- Cargo.lock | 149 ++--- Cargo.toml | 35 +- build/rust/goblin/Cargo.toml | 37 +- build/rust/scroll/Cargo.toml | 17 - build/rust/scroll/lib.rs | 11 - dom/chrome-webidl/UniFFI.webidl | 4 +- gfx/wr/Cargo.lock | 100 +-- gfx/wr/servo-tidy.toml | 2 - gfx/wr/webrender/Cargo.toml | 2 +- gfx/wr/wr_glyph_rasterizer/Cargo.toml | 2 +- .../src/main/java/ApplicationServices.kt | 2 +- .../src/main/java/DependenciesPlugin.kt | 2 +- .../plugins/dependencies/src/main/java/moz.yaml | 4 +- python/sites/mach.txt | 2 +- supply-chain/audits.toml | 5 - supply-chain/imports.lock | 294 +++------ .../rust/error-support/.cargo-checksum.json | 2 +- third_party/rust/error-support/Cargo.toml | 4 +- third_party/rust/glean-core/.cargo-checksum.json | 2 +- third_party/rust/glean-core/Cargo.toml | 6 +- .../rust/glean-core/src/common_metric_data.rs | 1 + third_party/rust/glean-core/src/core/mod.rs | 9 +- third_party/rust/glean-core/src/database/mod.rs | 1 + third_party/rust/glean-core/src/debug.rs | 1 + third_party/rust/glean-core/src/dispatcher/mod.rs | 5 +- third_party/rust/glean-core/src/error_recording.rs | 1 + .../rust/glean-core/src/event_database/mod.rs | 3 +- third_party/rust/glean-core/src/glean.udl | 1 - third_party/rust/glean-core/src/histogram/mod.rs | 1 + third_party/rust/glean-core/src/internal_pings.rs | 11 +- third_party/rust/glean-core/src/lib.rs | 5 +- third_party/rust/glean-core/src/lib_unit_tests.rs | 82 +-- third_party/rust/glean-core/src/metrics/event.rs | 16 +- .../rust/glean-core/src/metrics/memory_unit.rs | 2 + .../src/metrics/metrics_enabled_config.rs | 2 +- third_party/rust/glean-core/src/metrics/ping.rs | 31 - third_party/rust/glean-core/src/metrics/string.rs | 2 + third_party/rust/glean-core/src/metrics/text.rs | 2 + .../rust/glean-core/src/metrics/time_unit.rs | 1 + .../rust/glean-core/src/metrics/timespan.rs | 1 + .../glean-core/src/metrics/timing_distribution.rs | 2 +- third_party/rust/glean-core/src/metrics/url.rs | 2 + third_party/rust/glean-core/src/storage/mod.rs | 4 +- third_party/rust/glean-core/src/traits/event.rs | 1 + .../rust/glean-core/src/upload/directory.rs | 2 + third_party/rust/glean-core/src/upload/mod.rs | 4 + third_party/rust/glean-core/src/upload/request.rs | 2 +- third_party/rust/glean-core/tests/common/mod.rs | 1 - third_party/rust/glean-core/tests/event.rs | 1 - third_party/rust/glean-core/tests/ping_maker.rs | 2 - third_party/rust/glean/.cargo-checksum.json | 2 +- third_party/rust/glean/Cargo.toml | 4 +- third_party/rust/glean/src/common_test.rs | 1 + third_party/rust/glean/src/configuration.rs | 12 - third_party/rust/glean/src/lib.rs | 1 - third_party/rust/glean/tests/schema.rs | 3 +- third_party/rust/goblin/.cargo-checksum.json | 2 +- third_party/rust/goblin/CHANGELOG.md | 27 +- third_party/rust/goblin/Cargo.toml | 10 +- third_party/rust/goblin/README.md | 7 +- third_party/rust/goblin/src/elf/reloc.rs | 2 +- third_party/rust/goblin/src/error.rs | 7 - third_party/rust/goblin/src/lib.rs | 24 +- third_party/rust/goblin/src/mach/load_command.rs | 3 - third_party/rust/goblin/src/pe/authenticode.rs | 394 ++++------- .../rust/goblin/src/pe/certificate_table.rs | 28 +- third_party/rust/goblin/src/pe/data_directories.rs | 259 +++----- third_party/rust/goblin/src/pe/header.rs | 150 +---- third_party/rust/goblin/src/pe/mod.rs | 249 +------ third_party/rust/goblin/src/pe/optional_header.rs | 83 --- third_party/rust/goblin/src/pe/options.rs | 10 +- third_party/rust/goblin/src/pe/section_table.rs | 41 +- third_party/rust/goblin/src/pe/symbol.rs | 9 - third_party/rust/goblin/src/pe/utils.rs | 16 - third_party/rust/goblin/src/strtab.rs | 5 - .../rust/oneshot-uniffi/.cargo-checksum.json | 2 +- third_party/rust/oneshot-uniffi/CHANGELOG.md | 7 - third_party/rust/oneshot-uniffi/Cargo.lock | 2 +- third_party/rust/oneshot-uniffi/Cargo.toml | 2 +- third_party/rust/oneshot-uniffi/src/errors.rs | 15 +- third_party/rust/oneshot-uniffi/src/lib.rs | 51 +- third_party/rust/oneshot-uniffi/tests/raw.rs | 46 -- third_party/rust/relevancy/.cargo-checksum.json | 2 +- third_party/rust/relevancy/Cargo.toml | 4 +- .../rust/remote_settings/.cargo-checksum.json | 2 +- third_party/rust/remote_settings/Cargo.toml | 4 +- third_party/rust/remote_settings/src/client.rs | 54 +- third_party/rust/scroll/.cargo-checksum.json | 2 +- third_party/rust/scroll/CHANGELOG.md | 17 + third_party/rust/scroll/Cargo.lock | 205 ++++++ third_party/rust/scroll/Cargo.toml | 33 +- third_party/rust/scroll/README.md | 13 +- third_party/rust/scroll/benches/bench.rs | 157 +++++ third_party/rust/scroll/examples/data_ctx.rs | 24 + third_party/rust/scroll/src/ctx.rs | 107 +-- third_party/rust/scroll/src/endian.rs | 5 +- third_party/rust/scroll/src/error.rs | 26 +- third_party/rust/scroll/src/leb128.rs | 18 +- third_party/rust/scroll/src/lesser.rs | 7 +- third_party/rust/scroll/src/lib.rs | 67 +- third_party/rust/scroll/src/pread.rs | 7 +- third_party/rust/scroll/src/pwrite.rs | 9 +- third_party/rust/scroll/tests/api.rs | 292 ++++++++ .../rust/scroll_derive/.cargo-checksum.json | 2 +- third_party/rust/scroll_derive/Cargo.toml | 2 +- third_party/rust/scroll_derive/README.md | 2 +- third_party/rust/smawk/.cargo-checksum.json | 1 - third_party/rust/smawk/Cargo.toml | 53 -- third_party/rust/smawk/LICENSE | 21 - third_party/rust/smawk/README.md | 151 ----- third_party/rust/smawk/dprint.json | 19 - third_party/rust/smawk/rustfmt.toml | 2 - third_party/rust/smawk/src/brute_force.rs | 150 ----- third_party/rust/smawk/src/lib.rs | 570 ---------------- third_party/rust/smawk/src/monge.rs | 121 ---- third_party/rust/smawk/src/recursive.rs | 191 ------ third_party/rust/smawk/tests/agreement.rs | 104 --- third_party/rust/smawk/tests/complexity.rs | 83 --- third_party/rust/smawk/tests/monge.rs | 83 --- third_party/rust/smawk/tests/random_monge/mod.rs | 83 --- third_party/rust/smawk/tests/version-numbers.rs | 9 - third_party/rust/suggest/.cargo-checksum.json | 2 +- third_party/rust/suggest/Cargo.toml | 28 +- third_party/rust/suggest/benches/benchmark_all.rs | 25 - third_party/rust/suggest/src/benchmarks/README.md | 28 - third_party/rust/suggest/src/benchmarks/client.rs | 97 --- third_party/rust/suggest/src/benchmarks/ingest.rs | 116 ---- third_party/rust/suggest/src/benchmarks/mod.rs | 40 -- .../rust/suggest/src/bin/debug_ingestion_sizes.rs | 9 - third_party/rust/suggest/src/db.rs | 475 +++++++------ third_party/rust/suggest/src/lib.rs | 4 +- third_party/rust/suggest/src/rs.rs | 2 +- third_party/rust/suggest/src/schema.rs | 17 +- third_party/rust/suggest/src/store.rs | 300 +-------- third_party/rust/suggest/src/suggest.udl | 6 - third_party/rust/suggest/src/suggestion.rs | 31 - third_party/rust/sync15/.cargo-checksum.json | 2 +- third_party/rust/sync15/Cargo.toml | 4 +- third_party/rust/tabs/.cargo-checksum.json | 2 +- third_party/rust/tabs/Cargo.toml | 4 +- third_party/rust/textwrap/.cargo-checksum.json | 1 - third_party/rust/textwrap/CHANGELOG.md | 616 ----------------- third_party/rust/textwrap/Cargo.lock | 657 ------------------ third_party/rust/textwrap/Cargo.toml | 91 --- third_party/rust/textwrap/LICENSE | 21 - third_party/rust/textwrap/README.md | 176 ----- third_party/rust/textwrap/rustfmt.toml | 1 - third_party/rust/textwrap/src/columns.rs | 193 ------ third_party/rust/textwrap/src/core.rs | 461 ------------- third_party/rust/textwrap/src/fill.rs | 298 --------- third_party/rust/textwrap/src/fuzzing.rs | 23 - third_party/rust/textwrap/src/indentation.rs | 347 ---------- third_party/rust/textwrap/src/lib.rs | 235 ------- third_party/rust/textwrap/src/line_ending.rs | 88 --- third_party/rust/textwrap/src/options.rs | 300 --------- third_party/rust/textwrap/src/refill.rs | 352 ---------- third_party/rust/textwrap/src/termwidth.rs | 52 -- third_party/rust/textwrap/src/word_separators.rs | 481 -------------- third_party/rust/textwrap/src/word_splitters.rs | 314 --------- third_party/rust/textwrap/src/wrap.rs | 686 ------------------- third_party/rust/textwrap/src/wrap_algorithms.rs | 413 ------------ .../textwrap/src/wrap_algorithms/optimal_fit.rs | 433 ------------ third_party/rust/textwrap/tests/indent.rs | 88 --- third_party/rust/textwrap/tests/version-numbers.rs | 22 - .../rust/unicode-linebreak/.cargo-checksum.json | 1 - third_party/rust/unicode-linebreak/Cargo.toml | 32 - third_party/rust/unicode-linebreak/LICENSE | 201 ------ third_party/rust/unicode-linebreak/src/lib.rs | 160 ----- third_party/rust/unicode-linebreak/src/shared.rs | 134 ---- third_party/rust/unicode-linebreak/src/tables.rs | 10 - .../uniffi-example-arithmetic/.cargo-checksum.json | 2 +- .../rust/uniffi-example-arithmetic/Cargo.toml | 6 +- .../uniffi-example-geometry/.cargo-checksum.json | 2 +- .../rust/uniffi-example-geometry/Cargo.toml | 6 +- .../tests/bindings/test_geometry.py | 6 +- .../tests/bindings/test_geometry.rb | 6 +- .../uniffi-example-rondpoint/.cargo-checksum.json | 2 +- .../rust/uniffi-example-rondpoint/Cargo.toml | 6 +- .../tests/bindings/test_rondpoint.py | 2 +- .../tests/bindings/test_rondpoint.rb | 7 +- .../uniffi-example-sprites/.cargo-checksum.json | 2 +- third_party/rust/uniffi-example-sprites/Cargo.toml | 6 +- .../tests/bindings/test_sprites.py | 34 +- .../tests/bindings/test_sprites.rb | 44 +- .../uniffi-example-todolist/.cargo-checksum.json | 2 +- .../rust/uniffi-example-todolist/Cargo.toml | 6 +- .../tests/bindings/test_todolist.py | 4 +- .../tests/bindings/test_todolist.rb | 6 +- third_party/rust/uniffi/.cargo-checksum.json | 2 +- third_party/rust/uniffi/Cargo.toml | 11 +- third_party/rust/uniffi/README.md | 81 --- third_party/rust/uniffi/src/cli.rs | 21 +- third_party/rust/uniffi/src/lib.rs | 7 +- .../rust/uniffi_bindgen/.cargo-checksum.json | 2 +- third_party/rust/uniffi_bindgen/Cargo.toml | 15 +- third_party/rust/uniffi_bindgen/README.md | 81 --- .../rust/uniffi_bindgen/src/backend/filters.rs | 4 +- .../kotlin/gen_kotlin/callback_interface.rs | 2 +- .../src/bindings/kotlin/gen_kotlin/compounds.rs | 225 +++---- .../src/bindings/kotlin/gen_kotlin/executor.rs | 24 + .../src/bindings/kotlin/gen_kotlin/external.rs | 4 +- .../src/bindings/kotlin/gen_kotlin/mod.rs | 251 +------ .../{callback_interface.rs => object.rs} | 10 +- .../src/bindings/kotlin/gen_kotlin/primitives.rs | 10 +- .../src/bindings/kotlin/templates/Async.kt | 161 ++--- .../src/bindings/kotlin/templates/BooleanHelper.kt | 2 +- .../bindings/kotlin/templates/ByteArrayHelper.kt | 4 +- .../kotlin/templates/CallbackInterfaceImpl.kt | 117 ---- .../kotlin/templates/CallbackInterfaceRuntime.kt | 65 +- .../kotlin/templates/CallbackInterfaceTemplate.kt | 142 +++- .../kotlin/templates/CustomTypeTemplate.kt | 2 +- .../bindings/kotlin/templates/DurationHelper.kt | 2 +- .../src/bindings/kotlin/templates/EnumTemplate.kt | 30 +- .../src/bindings/kotlin/templates/ErrorTemplate.kt | 18 +- .../kotlin/templates/ExternalTypeTemplate.kt | 2 +- .../kotlin/templates/FfiConverterTemplate.kt | 6 +- .../src/bindings/kotlin/templates/Float32Helper.kt | 2 +- .../src/bindings/kotlin/templates/Float64Helper.kt | 2 +- .../kotlin/templates/ForeignExecutorTemplate.kt | 83 +++ .../src/bindings/kotlin/templates/HandleMap.kt | 27 - .../src/bindings/kotlin/templates/Helpers.kt | 152 +++-- .../src/bindings/kotlin/templates/Int16Helper.kt | 2 +- .../src/bindings/kotlin/templates/Int32Helper.kt | 2 +- .../src/bindings/kotlin/templates/Int64Helper.kt | 2 +- .../src/bindings/kotlin/templates/Int8Helper.kt | 2 +- .../src/bindings/kotlin/templates/Interface.kt | 14 - .../src/bindings/kotlin/templates/MapTemplate.kt | 4 +- .../kotlin/templates/NamespaceLibraryTemplate.kt | 61 +- .../kotlin/templates/ObjectCleanerHelper.kt | 40 -- .../kotlin/templates/ObjectCleanerHelperAndroid.kt | 26 - .../kotlin/templates/ObjectCleanerHelperJvm.kt | 25 - .../src/bindings/kotlin/templates/ObjectRuntime.kt | 161 +++++ .../bindings/kotlin/templates/ObjectTemplate.kt | 433 ++++-------- .../bindings/kotlin/templates/OptionalTemplate.kt | 6 +- .../src/bindings/kotlin/templates/README.md | 13 - .../bindings/kotlin/templates/RecordTemplate.kt | 29 +- .../kotlin/templates/RustBufferTemplate.kt | 39 +- .../bindings/kotlin/templates/SequenceTemplate.kt | 6 +- .../src/bindings/kotlin/templates/StringHelper.kt | 10 +- .../bindings/kotlin/templates/TimestampHelper.kt | 2 +- .../kotlin/templates/TopLevelFunctionTemplate.kt | 52 +- .../src/bindings/kotlin/templates/Types.kt | 40 +- .../src/bindings/kotlin/templates/UInt16Helper.kt | 2 +- .../src/bindings/kotlin/templates/UInt32Helper.kt | 2 +- .../src/bindings/kotlin/templates/UInt64Helper.kt | 2 +- .../src/bindings/kotlin/templates/UInt8Helper.kt | 2 +- .../src/bindings/kotlin/templates/macros.kt | 230 +++---- .../src/bindings/kotlin/templates/wrapper.kt | 4 - .../uniffi_bindgen/src/bindings/kotlin/test.rs | 16 +- .../src/bindings/python/gen_python/compounds.rs | 16 +- .../python/gen_python/{external.rs => executor.rs} | 16 +- .../src/bindings/python/gen_python/external.rs | 2 +- .../src/bindings/python/gen_python/mod.rs | 177 +---- .../src/bindings/python/templates/Async.py | 154 ++--- .../src/bindings/python/templates/BooleanHelper.py | 18 +- .../src/bindings/python/templates/BytesHelper.py | 5 +- .../python/templates/CallbackInterfaceImpl.py | 98 --- .../python/templates/CallbackInterfaceRuntime.py | 59 +- .../python/templates/CallbackInterfaceTemplate.py | 118 +++- .../src/bindings/python/templates/CustomType.py | 9 - .../bindings/python/templates/DurationHelper.py | 8 +- .../src/bindings/python/templates/EnumTemplate.py | 71 +- .../src/bindings/python/templates/ErrorTemplate.py | 19 - .../bindings/python/templates/ExternalTemplate.py | 8 +- .../src/bindings/python/templates/Float32Helper.py | 2 +- .../src/bindings/python/templates/Float64Helper.py | 2 +- .../python/templates/ForeignExecutorTemplate.py | 63 ++ .../src/bindings/python/templates/HandleMap.py | 33 - .../src/bindings/python/templates/Helpers.py | 36 +- .../src/bindings/python/templates/Int16Helper.py | 2 +- .../src/bindings/python/templates/Int32Helper.py | 2 +- .../src/bindings/python/templates/Int64Helper.py | 2 +- .../src/bindings/python/templates/Int8Helper.py | 2 +- .../src/bindings/python/templates/MapTemplate.py | 6 - .../python/templates/NamespaceLibraryTemplate.py | 45 +- .../bindings/python/templates/ObjectTemplate.py | 124 +--- .../bindings/python/templates/OptionalTemplate.py | 5 - .../bindings/python/templates/PointerManager.py | 68 ++ .../src/bindings/python/templates/Protocol.py | 9 - .../bindings/python/templates/RecordTemplate.py | 24 +- .../bindings/python/templates/RustBufferHelper.py | 18 +- .../python/templates/RustBufferTemplate.py | 11 +- .../bindings/python/templates/SequenceTemplate.py | 5 - .../src/bindings/python/templates/StringHelper.py | 4 +- .../bindings/python/templates/TimestampHelper.py | 4 - .../python/templates/TopLevelFunctionTemplate.py | 24 +- .../src/bindings/python/templates/Types.py | 5 +- .../src/bindings/python/templates/UInt16Helper.py | 2 +- .../src/bindings/python/templates/UInt32Helper.py | 2 +- .../src/bindings/python/templates/UInt64Helper.py | 2 +- .../src/bindings/python/templates/UInt8Helper.py | 2 +- .../src/bindings/python/templates/macros.py | 95 +-- .../src/bindings/python/templates/wrapper.py | 17 +- .../uniffi_bindgen/src/bindings/python/test.rs | 14 +- .../src/bindings/ruby/gen_ruby/mod.rs | 79 +-- .../src/bindings/ruby/templates/ObjectTemplate.rb | 36 +- .../src/bindings/ruby/templates/RecordTemplate.rb | 7 +- .../bindings/ruby/templates/RustBufferBuilder.rb | 2 +- .../bindings/ruby/templates/RustBufferStream.rb | 4 +- .../bindings/ruby/templates/RustBufferTemplate.rb | 42 +- .../ruby/templates/TopLevelFunctionTemplate.rb | 4 +- .../src/bindings/ruby/templates/macros.rb | 10 +- .../rust/uniffi_bindgen/src/bindings/ruby/test.rs | 15 +- .../bindings/swift/gen_swift/callback_interface.rs | 12 +- .../src/bindings/swift/gen_swift/compounds.rs | 5 +- .../external.rs => swift/gen_swift/executor.rs} | 21 +- .../src/bindings/swift/gen_swift/external.rs | 2 +- .../src/bindings/swift/gen_swift/mod.rs | 209 ++---- .../external.rs => swift/gen_swift/object.rs} | 16 +- .../src/bindings/swift/gen_swift/primitives.rs | 8 +- .../src/bindings/swift/templates/Async.swift | 178 ++--- .../swift/templates/BridgingHeaderTemplate.h | 48 +- .../swift/templates/CallbackInterfaceImpl.swift | 113 ---- .../swift/templates/CallbackInterfaceRuntime.swift | 57 ++ .../templates/CallbackInterfaceTemplate.swift | 145 +++- .../bindings/swift/templates/EnumTemplate.swift | 27 +- .../bindings/swift/templates/ErrorTemplate.swift | 12 +- .../swift/templates/ForeignExecutorTemplate.swift | 69 ++ .../src/bindings/swift/templates/HandleMap.swift | 40 -- .../src/bindings/swift/templates/Helpers.swift | 44 +- .../bindings/swift/templates/ObjectTemplate.swift | 333 ++++------ .../src/bindings/swift/templates/Protocol.swift | 12 - .../bindings/swift/templates/RecordTemplate.swift | 17 +- .../swift/templates/RustBufferTemplate.swift | 4 - .../swift/templates/TopLevelFunctionTemplate.swift | 49 +- .../src/bindings/swift/templates/Types.swift | 3 + .../src/bindings/swift/templates/macros.swift | 271 +++----- .../src/bindings/swift/templates/wrapper.swift | 8 - .../rust/uniffi_bindgen/src/bindings/swift/test.rs | 24 +- .../rust/uniffi_bindgen/src/interface/callbacks.rs | 471 +++++-------- .../rust/uniffi_bindgen/src/interface/enum_.rs | 224 +------ .../rust/uniffi_bindgen/src/interface/ffi.rs | 195 +----- .../rust/uniffi_bindgen/src/interface/function.rs | 32 - .../rust/uniffi_bindgen/src/interface/mod.rs | 342 ++++------ .../rust/uniffi_bindgen/src/interface/object.rs | 199 +----- .../rust/uniffi_bindgen/src/interface/record.rs | 53 -- .../rust/uniffi_bindgen/src/interface/universe.rs | 5 +- third_party/rust/uniffi_bindgen/src/lib.rs | 138 +--- .../rust/uniffi_bindgen/src/library_mode.rs | 40 +- .../rust/uniffi_bindgen/src/macro_metadata/ci.rs | 21 +- .../uniffi_bindgen/src/macro_metadata/extract.rs | 2 +- .../rust/uniffi_bindgen/src/scaffolding/mod.rs | 36 +- .../templates/CallbackInterfaceTemplate.rs | 99 ++- .../src/scaffolding/templates/EnumTemplate.rs | 13 +- .../src/scaffolding/templates/ErrorTemplate.rs | 10 +- .../scaffolding/templates/ExternalTypesTemplate.rs | 2 - .../src/scaffolding/templates/ObjectTemplate.rs | 34 +- .../src/scaffolding/templates/RecordTemplate.rs | 8 +- .../templates/TopLevelFunctionTemplate.rs | 5 +- third_party/rust/uniffi_build/.cargo-checksum.json | 2 +- third_party/rust/uniffi_build/Cargo.toml | 5 +- third_party/rust/uniffi_build/README.md | 81 --- .../uniffi_checksum_derive/.cargo-checksum.json | 2 +- third_party/rust/uniffi_checksum_derive/Cargo.toml | 3 +- third_party/rust/uniffi_checksum_derive/README.md | 81 --- third_party/rust/uniffi_core/.cargo-checksum.json | 2 +- third_party/rust/uniffi_core/Cargo.toml | 6 +- third_party/rust/uniffi_core/README.md | 81 --- .../rust/uniffi_core/src/ffi/callbackinterface.rs | 125 +++- third_party/rust/uniffi_core/src/ffi/ffidefault.rs | 11 +- .../rust/uniffi_core/src/ffi/foreigncallbacks.rs | 116 +++- .../rust/uniffi_core/src/ffi/foreignexecutor.rs | 487 ++++++++++++++ .../rust/uniffi_core/src/ffi/foreignfuture.rs | 241 ------- third_party/rust/uniffi_core/src/ffi/handle.rs | 46 -- third_party/rust/uniffi_core/src/ffi/mod.rs | 6 +- third_party/rust/uniffi_core/src/ffi/rustbuffer.rs | 122 +++- third_party/rust/uniffi_core/src/ffi/rustcalls.rs | 9 +- third_party/rust/uniffi_core/src/ffi/rustfuture.rs | 735 +++++++++++++++++++++ .../rust/uniffi_core/src/ffi/rustfuture/future.rs | 320 --------- .../rust/uniffi_core/src/ffi/rustfuture/mod.rs | 141 ---- .../uniffi_core/src/ffi/rustfuture/scheduler.rs | 96 --- .../rust/uniffi_core/src/ffi/rustfuture/tests.rs | 223 ------- .../rust/uniffi_core/src/ffi_converter_impls.rs | 75 ++- .../rust/uniffi_core/src/ffi_converter_traits.rs | 151 +---- third_party/rust/uniffi_core/src/lib.rs | 6 +- third_party/rust/uniffi_core/src/metadata.rs | 53 +- .../rust/uniffi_macros/.cargo-checksum.json | 2 +- third_party/rust/uniffi_macros/Cargo.toml | 10 +- third_party/rust/uniffi_macros/README.md | 81 --- third_party/rust/uniffi_macros/src/default.rs | 133 ---- third_party/rust/uniffi_macros/src/enum_.rs | 566 ++++++---------- third_party/rust/uniffi_macros/src/error.rs | 101 +-- third_party/rust/uniffi_macros/src/export.rs | 211 ++++-- .../rust/uniffi_macros/src/export/attributes.rs | 576 +++++----------- .../uniffi_macros/src/export/callback_interface.rs | 438 +++++------- third_party/rust/uniffi_macros/src/export/item.rs | 88 +-- .../rust/uniffi_macros/src/export/scaffolding.rs | 123 ++-- .../uniffi_macros/src/export/trait_interface.rs | 183 ----- .../rust/uniffi_macros/src/export/utrait.rs | 23 +- third_party/rust/uniffi_macros/src/fnsig.rs | 248 ++----- third_party/rust/uniffi_macros/src/lib.rs | 73 +- third_party/rust/uniffi_macros/src/object.rs | 76 +-- third_party/rust/uniffi_macros/src/record.rs | 113 +++- .../rust/uniffi_macros/src/setup_scaffolding.rs | 57 +- third_party/rust/uniffi_macros/src/util.rs | 47 +- third_party/rust/uniffi_meta/.cargo-checksum.json | 2 +- third_party/rust/uniffi_meta/Cargo.toml | 5 +- third_party/rust/uniffi_meta/README.md | 81 --- third_party/rust/uniffi_meta/src/ffi_names.rs | 13 +- third_party/rust/uniffi_meta/src/group.rs | 9 +- third_party/rust/uniffi_meta/src/lib.rs | 65 +- third_party/rust/uniffi_meta/src/metadata.rs | 13 +- third_party/rust/uniffi_meta/src/reader.rs | 148 +---- third_party/rust/uniffi_meta/src/types.rs | 22 +- .../rust/uniffi_testing/.cargo-checksum.json | 2 +- third_party/rust/uniffi_testing/Cargo.toml | 2 +- third_party/rust/uniffi_udl/.cargo-checksum.json | 2 +- third_party/rust/uniffi_udl/Cargo.toml | 12 +- third_party/rust/uniffi_udl/README.md | 81 --- third_party/rust/uniffi_udl/src/attributes.rs | 199 +----- third_party/rust/uniffi_udl/src/collectors.rs | 18 +- .../rust/uniffi_udl/src/converters/callables.rs | 16 +- .../rust/uniffi_udl/src/converters/enum_.rs | 79 ++- .../rust/uniffi_udl/src/converters/interface.rs | 6 +- third_party/rust/uniffi_udl/src/converters/mod.rs | 10 - third_party/rust/uniffi_udl/src/finder.rs | 60 +- third_party/rust/uniffi_udl/src/lib.rs | 2 +- third_party/rust/uniffi_udl/src/literal.rs | 8 +- third_party/rust/uniffi_udl/src/resolver.rs | 1 + .../rust/webext-storage/.cargo-checksum.json | 2 +- third_party/rust/webext-storage/Cargo.toml | 4 +- third_party/rust/weedle2/.cargo-checksum.json | 2 +- third_party/rust/weedle2/Cargo.toml | 5 +- third_party/rust/weedle2/README.md | 2 +- third_party/rust/weedle2/src/common.rs | 45 -- third_party/rust/weedle2/src/dictionary.rs | 3 +- third_party/rust/weedle2/src/interface.rs | 4 +- third_party/rust/weedle2/src/lib.rs | 16 +- third_party/rust/weedle2/src/namespace.rs | 4 +- third_party/rust/weedle2/src/whitespace.rs | 1 - toolkit/components/glean/Cargo.toml | 2 +- toolkit/components/glean/api/Cargo.toml | 2 +- toolkit/components/glean/api/src/common_test.rs | 1 - toolkit/components/glean/src/init/mod.rs | 1 - .../components/uniffi-bindgen-gecko-js/Cargo.toml | 2 +- .../components/generated/RustRelevancy.sys.mjs | 10 +- .../generated/RustRemoteSettings.sys.mjs | 10 +- .../components/generated/RustSuggest.sys.mjs | 71 +- .../components/generated/RustTabs.sys.mjs | 40 +- .../components/uniffi-bindgen-gecko-js/config.toml | 23 +- .../fixtures/generated/RustArithmetic.sys.mjs | 8 +- .../fixtures/generated/RustCustomTypes.sys.mjs | 2 +- .../fixtures/generated/RustExternalTypes.sys.mjs | 4 +- .../fixtures/generated/RustGeometry.sys.mjs | 4 +- .../fixtures/generated/RustRondpoint.sys.mjs | 126 ++-- .../fixtures/generated/RustSprites.sys.mjs | 14 +- .../fixtures/generated/RustTodolist.sys.mjs | 32 +- .../fixtures/tests/xpcshell/xpcshell.toml | 5 +- .../uniffi-bindgen-gecko-js/src/render/cpp.rs | 40 +- .../uniffi-bindgen-gecko-js/src/render/js.rs | 4 +- .../src/templates/UniFFIScaffolding.cpp | 3 +- .../src/templates/js/Object.sys.mjs | 2 +- .../uniffi-fixture-external-types/Cargo.toml | 2 +- toolkit/components/uniffi-js/OwnedRustBuffer.cpp | 4 +- .../uniffi-js/UniFFIFixtureScaffolding.cpp | 465 +++++++------ .../uniffi-js/UniFFIGeneratedScaffolding.cpp | 254 +++---- toolkit/components/uniffi-js/UniFFIPointer.cpp | 9 - toolkit/components/uniffi-js/UniFFIPointer.h | 2 - toolkit/components/uniffi-js/UniFFIPointerType.h | 4 +- toolkit/components/uniffi-js/UniFFIRust.h | 6 +- toolkit/library/rust/shared/Cargo.toml | 12 +- toolkit/library/rust/shared/lib.rs | 2 +- tools/lint/trojan-source.yml | 1 - 464 files changed, 8100 insertions(+), 21736 deletions(-) rewrite build/rust/goblin/Cargo.toml (75%) delete mode 100644 build/rust/scroll/Cargo.toml delete mode 100644 build/rust/scroll/lib.rs rewrite third_party/rust/goblin/src/pe/authenticode.rs (78%) rewrite third_party/rust/goblin/src/pe/data_directories.rs (75%) delete mode 100644 third_party/rust/oneshot-uniffi/tests/raw.rs rewrite third_party/rust/scroll/.cargo-checksum.json (100%) create mode 100644 third_party/rust/scroll/CHANGELOG.md create mode 100644 third_party/rust/scroll/Cargo.lock create mode 100644 third_party/rust/scroll/benches/bench.rs create mode 100644 third_party/rust/scroll/examples/data_ctx.rs create mode 100644 third_party/rust/scroll/tests/api.rs rewrite third_party/rust/scroll_derive/.cargo-checksum.json (84%) delete mode 100644 third_party/rust/smawk/.cargo-checksum.json delete mode 100644 third_party/rust/smawk/Cargo.toml delete mode 100644 third_party/rust/smawk/LICENSE delete mode 100644 third_party/rust/smawk/README.md delete mode 100644 third_party/rust/smawk/dprint.json delete mode 100644 third_party/rust/smawk/rustfmt.toml delete mode 100644 third_party/rust/smawk/src/brute_force.rs delete mode 100644 third_party/rust/smawk/src/lib.rs delete mode 100644 third_party/rust/smawk/src/monge.rs delete mode 100644 third_party/rust/smawk/src/recursive.rs delete mode 100644 third_party/rust/smawk/tests/agreement.rs delete mode 100644 third_party/rust/smawk/tests/complexity.rs delete mode 100644 third_party/rust/smawk/tests/monge.rs delete mode 100644 third_party/rust/smawk/tests/random_monge/mod.rs delete mode 100644 third_party/rust/smawk/tests/version-numbers.rs rewrite third_party/rust/suggest/.cargo-checksum.json (100%) delete mode 100644 third_party/rust/suggest/benches/benchmark_all.rs delete mode 100644 third_party/rust/suggest/src/benchmarks/README.md delete mode 100644 third_party/rust/suggest/src/benchmarks/client.rs delete mode 100644 third_party/rust/suggest/src/benchmarks/ingest.rs delete mode 100644 third_party/rust/suggest/src/benchmarks/mod.rs delete mode 100644 third_party/rust/suggest/src/bin/debug_ingestion_sizes.rs delete mode 100644 third_party/rust/textwrap/.cargo-checksum.json delete mode 100644 third_party/rust/textwrap/CHANGELOG.md delete mode 100644 third_party/rust/textwrap/Cargo.lock delete mode 100644 third_party/rust/textwrap/Cargo.toml delete mode 100644 third_party/rust/textwrap/LICENSE delete mode 100644 third_party/rust/textwrap/README.md delete mode 100644 third_party/rust/textwrap/rustfmt.toml delete mode 100644 third_party/rust/textwrap/src/columns.rs delete mode 100644 third_party/rust/textwrap/src/core.rs delete mode 100644 third_party/rust/textwrap/src/fill.rs delete mode 100644 third_party/rust/textwrap/src/fuzzing.rs delete mode 100644 third_party/rust/textwrap/src/indentation.rs delete mode 100644 third_party/rust/textwrap/src/lib.rs delete mode 100644 third_party/rust/textwrap/src/line_ending.rs delete mode 100644 third_party/rust/textwrap/src/options.rs delete mode 100644 third_party/rust/textwrap/src/refill.rs delete mode 100644 third_party/rust/textwrap/src/termwidth.rs delete mode 100644 third_party/rust/textwrap/src/word_separators.rs delete mode 100644 third_party/rust/textwrap/src/word_splitters.rs delete mode 100644 third_party/rust/textwrap/src/wrap.rs delete mode 100644 third_party/rust/textwrap/src/wrap_algorithms.rs delete mode 100644 third_party/rust/textwrap/src/wrap_algorithms/optimal_fit.rs delete mode 100644 third_party/rust/textwrap/tests/indent.rs delete mode 100644 third_party/rust/textwrap/tests/version-numbers.rs delete mode 100644 third_party/rust/unicode-linebreak/.cargo-checksum.json delete mode 100644 third_party/rust/unicode-linebreak/Cargo.toml delete mode 100644 third_party/rust/unicode-linebreak/LICENSE delete mode 100644 third_party/rust/unicode-linebreak/src/lib.rs delete mode 100644 third_party/rust/unicode-linebreak/src/shared.rs delete mode 100644 third_party/rust/unicode-linebreak/src/tables.rs rewrite third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.py (88%) rewrite third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.rb (75%) rewrite third_party/rust/uniffi/.cargo-checksum.json (100%) delete mode 100644 third_party/rust/uniffi/README.md rewrite third_party/rust/uniffi_bindgen/.cargo-checksum.json (98%) delete mode 100644 third_party/rust/uniffi_bindgen/README.md rewrite third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/compounds.rs (61%) create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/executor.rs copy third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/{callback_interface.rs => object.rs} (69%) rewrite third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Async.kt (88%) delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt rewrite third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt (74%) create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ForeignExecutorTemplate.kt delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/HandleMap.kt delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Interface.kt delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelper.kt delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperAndroid.kt delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperJvm.kt create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectRuntime.kt rewrite third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectTemplate.kt (91%) delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/README.md rewrite third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/TopLevelFunctionTemplate.kt (100%) rewrite third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/macros.kt (74%) copy third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/{external.rs => executor.rs} (55%) rewrite third_party/rust/uniffi_bindgen/src/bindings/python/templates/Async.py (75%) delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceImpl.py rewrite third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceTemplate.py (83%) create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/ForeignExecutorTemplate.py delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/HandleMap.py create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/PointerManager.py delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/Protocol.py copy third_party/rust/uniffi_bindgen/src/bindings/{python/gen_python/external.rs => swift/gen_swift/executor.rs} (51%) copy third_party/rust/uniffi_bindgen/src/bindings/{python/gen_python/external.rs => swift/gen_swift/object.rs} (57%) rewrite third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Async.swift (76%) delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceImpl.swift create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ForeignExecutorTemplate.swift delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/templates/HandleMap.swift rewrite third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ObjectTemplate.swift (68%) delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Protocol.swift rewrite third_party/rust/uniffi_bindgen/src/bindings/swift/templates/TopLevelFunctionTemplate.swift (100%) rewrite third_party/rust/uniffi_bindgen/src/bindings/swift/templates/macros.swift (65%) rewrite third_party/rust/uniffi_bindgen/src/interface/callbacks.rs (61%) rewrite third_party/rust/uniffi_bindgen/src/scaffolding/templates/CallbackInterfaceTemplate.rs (83%) delete mode 100644 third_party/rust/uniffi_build/README.md delete mode 100644 third_party/rust/uniffi_checksum_derive/README.md rewrite third_party/rust/uniffi_core/.cargo-checksum.json (100%) delete mode 100644 third_party/rust/uniffi_core/README.md create mode 100644 third_party/rust/uniffi_core/src/ffi/foreignexecutor.rs delete mode 100644 third_party/rust/uniffi_core/src/ffi/foreignfuture.rs delete mode 100644 third_party/rust/uniffi_core/src/ffi/handle.rs create mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture.rs delete mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture/future.rs delete mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture/mod.rs delete mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture/scheduler.rs delete mode 100644 third_party/rust/uniffi_core/src/ffi/rustfuture/tests.rs rewrite third_party/rust/uniffi_macros/.cargo-checksum.json (100%) delete mode 100644 third_party/rust/uniffi_macros/README.md delete mode 100644 third_party/rust/uniffi_macros/src/default.rs rewrite third_party/rust/uniffi_macros/src/enum_.rs (69%) rewrite third_party/rust/uniffi_macros/src/export/attributes.rs (66%) rewrite third_party/rust/uniffi_macros/src/export/callback_interface.rs (63%) delete mode 100644 third_party/rust/uniffi_macros/src/export/trait_interface.rs rewrite third_party/rust/uniffi_meta/.cargo-checksum.json (100%) delete mode 100644 third_party/rust/uniffi_meta/README.md rewrite third_party/rust/uniffi_udl/.cargo-checksum.json (100%) delete mode 100644 third_party/rust/uniffi_udl/README.md rewrite third_party/rust/weedle2/.cargo-checksum.json (61%) diff --git a/.cargo/config.toml.in b/.cargo/config.toml.in index cb2094d66f7b..ac39dbea00b9 100644 --- a/.cargo/config.toml.in +++ b/.cargo/config.toml.in @@ -55,9 +55,9 @@ git = "https://github.com/mozilla-spidermonkey/jsparagus" rev = "61f399c53a641ebd3077c1f39f054f6d396a633c" replace-with = "vendored-sources" -[source."git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584"] +[source."git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706"] git = "https://github.com/mozilla/application-services" -rev = "e6ccfed09ebe663f464a33968f42e656c152e584" +rev = "9054db4bb5031881550ceab3448665ef6499a706" replace-with = "vendored-sources" [source."git+https://github.com/mozilla/audioipc?rev=409e11f8de6288e9ddfe269654523735302e59e6"] @@ -90,9 +90,9 @@ git = "https://github.com/mozilla/neqo" tag = "v0.7.2" replace-with = "vendored-sources" -[source."git+https://github.com/mozilla/uniffi-rs.git?rev=d52c5460ae42ecad1e73a5b394ac96d48f4769de"] +[source."git+https://github.com/mozilla/uniffi-rs.git?rev=afb29ebdc1d9edf15021b1c5332fc9f285bbe13b"] git = "https://github.com/mozilla/uniffi-rs.git" -rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de" +rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b" replace-with = "vendored-sources" [source."git+https://github.com/seanmonstar/warp?rev=9d081461ae1167eb321585ce424f4fef6cf0092b"] diff --git a/Cargo.lock b/Cargo.lock index 83d1b6866d6e..8d2ca9096cd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1655,7 +1655,7 @@ dependencies = [ [[package]] name = "error-support" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "error-support-macros", "lazy_static", @@ -1667,7 +1667,7 @@ dependencies = [ [[package]] name = "error-support-macros" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "proc-macro2", "quote", @@ -2369,9 +2369,9 @@ dependencies = [ [[package]] name = "glean" -version = "59.0.0" +version = "58.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceede8fb9c90ba1b77fb8290d3ae7b62bfcb422ad1d6e46bae1c8af3f22f12d" +checksum = "f58388f10d013e2d12bb58e6e76983ede120789956fe827913a3d2560c66d44d" dependencies = [ "glean-core", "inherent", @@ -2382,9 +2382,9 @@ dependencies = [ [[package]] name = "glean-core" -version = "59.0.0" +version = "58.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea06a592b1395e0a16a5f4d6872f009ca7c98acc5127a8119088f1b435b5aaae" +checksum = "ed9acc46fd38c5c995a0537e76364496addace660839dc279079e5957e3c1093" dependencies = [ "android_logger", "bincode", @@ -2446,20 +2446,20 @@ dependencies = [ [[package]] name = "goblin" -version = "0.7.999" +version = "0.6.999" dependencies = [ - "goblin 0.8.0", + "goblin 0.7.1", ] [[package]] name = "goblin" -version = "0.8.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07a4ffed2093b118a525b1d8f5204ae274faed5604537caf7135d0f18d9887" +checksum = "f27c1b4369c2cd341b5de549380158b105a04c331be5db9110eef7b6d2742134" dependencies = [ "log", "plain", - "scroll 0.12.0", + "scroll", ] [[package]] @@ -2934,7 +2934,7 @@ dependencies = [ [[package]] name = "interrupt-support" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "lazy_static", "parking_lot", @@ -3618,7 +3618,7 @@ dependencies = [ "num-derive", "num-traits", "range-map", - "scroll 0.11.999", + "scroll", "smart-default", ] @@ -3632,7 +3632,7 @@ dependencies = [ "byteorder", "cfg-if 1.0.0", "crash-context", - "goblin 0.7.999", + "goblin 0.7.1", "libc", "mach2", "memmap2 0.8.999", @@ -3640,7 +3640,7 @@ dependencies = [ "minidump-common", "nix 0.27.1", "procfs-core", - "scroll 0.11.999", + "scroll", "tempfile", "thiserror", ] @@ -4129,7 +4129,7 @@ dependencies = [ [[package]] name = "nss_build_common" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" [[package]] name = "nsstring" @@ -4252,9 +4252,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oneshot-uniffi" -version = "0.1.6" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c" +checksum = "9ae4988774e7a7e6a0783d119bdc683ea8c1d01a24d4fff9b4bdc280e07bd99e" [[package]] name = "ordered-float" @@ -4573,7 +4573,7 @@ dependencies = [ name = "process_reader" version = "0.1.0" dependencies = [ - "goblin 0.7.999", + "goblin 0.7.1", "libc", "mach2", "memoffset 0.9.0", @@ -4814,7 +4814,7 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "relevancy" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "error-support", "log", @@ -4830,7 +4830,7 @@ dependencies = [ [[package]] name = "remote_settings" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "parking_lot", "serde", @@ -5055,25 +5055,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scroll" -version = "0.11.999" -dependencies = [ - "scroll 0.12.0", -] - -[[package]] -name = "scroll" -version = "0.12.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" dependencies = [ "scroll_derive", ] [[package]] name = "scroll_derive" -version = "0.12.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", @@ -5329,12 +5322,6 @@ dependencies = [ ] [[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - -[[package]] name = "smoosh" version = "0.1.0" dependencies = [ @@ -5366,7 +5353,7 @@ dependencies = [ [[package]] name = "sql-support" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "ffi-support", "interrupt-support", @@ -5547,7 +5534,7 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "suggest" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "anyhow", "chrono", @@ -5596,7 +5583,7 @@ dependencies = [ [[package]] name = "sync-guid" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "base64 0.21.3", "rand", @@ -5607,7 +5594,7 @@ dependencies = [ [[package]] name = "sync15" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "anyhow", "error-support", @@ -5639,7 +5626,7 @@ dependencies = [ [[package]] name = "tabs" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "anyhow", "error-support", @@ -5685,17 +5672,6 @@ name = "terminal_size" version = "0.3.999" [[package]] -name = "textwrap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" -dependencies = [ - "smawk", - "unicode-linebreak", - "unicode-width", -] - -[[package]] name = "thin-vec" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6011,12 +5987,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] name = "unicode-normalization" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6039,9 +6009,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "uniffi" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5566fae48a5cb017005bf9cd622af5236b2a203a13fb548afde3506d3c68277" +checksum = "21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f" dependencies = [ "anyhow", "uniffi_build", @@ -6068,7 +6038,7 @@ dependencies = [ [[package]] name = "uniffi-example-arithmetic" version = "0.22.0" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d52c5460ae42ecad1e73a5b394ac96d48f4769de#d52c5460ae42ecad1e73a5b394ac96d48f4769de" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=afb29ebdc1d9edf15021b1c5332fc9f285bbe13b#afb29ebdc1d9edf15021b1c5332fc9f285bbe13b" dependencies = [ "thiserror", "uniffi", @@ -6088,7 +6058,7 @@ dependencies = [ [[package]] name = "uniffi-example-geometry" version = "0.22.0" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d52c5460ae42ecad1e73a5b394ac96d48f4769de#d52c5460ae42ecad1e73a5b394ac96d48f4769de" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=afb29ebdc1d9edf15021b1c5332fc9f285bbe13b#afb29ebdc1d9edf15021b1c5332fc9f285bbe13b" dependencies = [ "uniffi", ] @@ -6096,7 +6066,7 @@ dependencies = [ [[package]] name = "uniffi-example-rondpoint" version = "0.22.0" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d52c5460ae42ecad1e73a5b394ac96d48f4769de#d52c5460ae42ecad1e73a5b394ac96d48f4769de" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=afb29ebdc1d9edf15021b1c5332fc9f285bbe13b#afb29ebdc1d9edf15021b1c5332fc9f285bbe13b" dependencies = [ "uniffi", ] @@ -6104,7 +6074,7 @@ dependencies = [ [[package]] name = "uniffi-example-sprites" version = "0.22.0" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d52c5460ae42ecad1e73a5b394ac96d48f4769de#d52c5460ae42ecad1e73a5b394ac96d48f4769de" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=afb29ebdc1d9edf15021b1c5332fc9f285bbe13b#afb29ebdc1d9edf15021b1c5332fc9f285bbe13b" dependencies = [ "uniffi", ] @@ -6112,7 +6082,7 @@ dependencies = [ [[package]] name = "uniffi-example-todolist" version = "0.22.0" -source = "git+https://github.com/mozilla/uniffi-rs.git?rev=d52c5460ae42ecad1e73a5b394ac96d48f4769de#d52c5460ae42ecad1e73a5b394ac96d48f4769de" +source = "git+https://github.com/mozilla/uniffi-rs.git?rev=afb29ebdc1d9edf15021b1c5332fc9f285bbe13b#afb29ebdc1d9edf15021b1c5332fc9f285bbe13b" dependencies = [ "once_cell", "thiserror", @@ -6138,9 +6108,9 @@ dependencies = [ [[package]] name = "uniffi_bindgen" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a77bb514bcd4bf27c9bd404d7c3f2a6a8131b957eba9c22cfeb7751c4278e09" +checksum = "fd992f2929a053829d5875af1eff2ee3d7a7001cb3b9a46cc7895f2caede6940" dependencies = [ "anyhow", "askama", @@ -6148,12 +6118,11 @@ dependencies = [ "cargo_metadata", "fs-err", "glob", - "goblin 0.8.0", + "goblin 0.6.999", "heck", "once_cell", "paste", "serde", - "textwrap", "toml", "uniffi_meta", "uniffi_testing", @@ -6162,9 +6131,9 @@ dependencies = [ [[package]] name = "uniffi_build" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45cba427aeb7b3a8b54830c4c915079a7a3c62608dd03dddba1d867a8a023eb4" +checksum = "001964dd3682d600084b3aaf75acf9c3426699bc27b65e96bb32d175a31c74e9" dependencies = [ "anyhow", "camino", @@ -6173,9 +6142,9 @@ dependencies = [ [[package]] name = "uniffi_checksum_derive" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae7e5a6c33b1dec3f255f57ec0b6af0f0b2bb3021868be1d5eec7a38e2905ebc" +checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c" dependencies = [ "quote", "syn", @@ -6183,9 +6152,9 @@ dependencies = [ [[package]] name = "uniffi_core" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea3eb5474d50fc149b7e4d86b9c5bd4a61dcc167f0683902bf18ae7bbb3deef" +checksum = "6121a127a3af1665cd90d12dd2b3683c2643c5103281d0fed5838324ca1fad5b" dependencies = [ "anyhow", "bytes", @@ -6199,9 +6168,9 @@ dependencies = [ [[package]] name = "uniffi_macros" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18331d35003f46f0d04047fbe4227291815b83a937a8c32bc057f990962182c4" +checksum = "11cf7a58f101fcedafa5b77ea037999b88748607f0ef3a33eaa0efc5392e92e4" dependencies = [ "bincode", "camino", @@ -6212,14 +6181,15 @@ dependencies = [ "serde", "syn", "toml", + "uniffi_build", "uniffi_meta", ] [[package]] name = "uniffi_meta" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7224422c4cfd181c7ca9fca2154abca4d21db962f926f270f996edd38b0c4b8" +checksum = "71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2" dependencies = [ "anyhow", "bytes", @@ -6229,9 +6199,9 @@ dependencies = [ [[package]] name = "uniffi_testing" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ce878d0bdfc288b58797044eaaedf748526c56eef3575380bb4d4b19d69eee" +checksum = "118448debffcb676ddbe8c5305fb933ab7e0123753e659a71dc4a693f8d9f23c" dependencies = [ "anyhow", "camino", @@ -6242,12 +6212,11 @@ dependencies = [ [[package]] name = "uniffi_udl" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c43c9ed40a8d20a5c3eae2d23031092db6b96dc8e571beb449ba9757484cea0" +checksum = "889edb7109c6078abe0e53e9b4070cf74a6b3468d141bdf5ef1bd4d1dc24a1c3" dependencies = [ "anyhow", - "textwrap", "uniffi_meta", "uniffi_testing", "weedle2", @@ -6309,7 +6278,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "viaduct" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "ffi-support", "log", @@ -6457,7 +6426,7 @@ dependencies = [ [[package]] name = "webext-storage" version = "0.1.0" -source = "git+https://github.com/mozilla/application-services?rev=e6ccfed09ebe663f464a33968f42e656c152e584#e6ccfed09ebe663f464a33968f42e656c152e584" +source = "git+https://github.com/mozilla/application-services?rev=9054db4bb5031881550ceab3448665ef6499a706#9054db4bb5031881550ceab3448665ef6499a706" dependencies = [ "anyhow", "error-support", @@ -6607,9 +6576,9 @@ dependencies = [ [[package]] name = "weedle2" -version = "5.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +checksum = "2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741" dependencies = [ "nom", ] diff --git a/Cargo.toml b/Cargo.toml index 441e8c66b15e..7b26009e165d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,8 +53,7 @@ resolver = "2" [workspace.dependencies] # Shared across multiple UniFFI consumers. -uniffi = "0.27.1" -uniffi_bindgen = "0.27.1" +uniffi = "0.25.3" # Shared across multiple application-services consumers. rusqlite = "0.30.0" @@ -165,12 +164,10 @@ derive_more = { path = "build/rust/derive_more" } # Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30 autocfg = { path = "third_party/rust/autocfg" } -# Patch goblin 0.7.0 to 0.8 +# Patch goblin 0.6.0 to 0.7.0 because uniffi crates still use the older version +# and we want to avoid duplications goblin = { path = "build/rust/goblin" } -# Patch scroll 0.11 to 0.12 -scroll = { path = "build/rust/scroll" } - # Patch memoffset from 0.8.0 to 0.9.0 since it's compatible and it avoids duplication memoffset = { path = "build/rust/memoffset" } @@ -212,14 +209,14 @@ warp = { git = "https://github.com/seanmonstar/warp", rev = "9d081461ae1167eb321 malloc_size_of_derive = { path = "xpcom/rust/malloc_size_of_derive" } # application-services overrides to make updating them all simpler. -interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } -relevancy = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } -sql-support = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } -suggest = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } -sync15 = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } -tabs = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } -viaduct = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } -webext-storage = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } +interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } +relevancy = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } +sql-support = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } +suggest = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } +sync15 = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } +tabs = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } +viaduct = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } +webext-storage = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } # Patch mio 0.8.8 to use windows-sys 0.52 (backport https://github.com/tokio-rs/mio/commit/eea9e3e0c469480e5c59c01e6c3c7e5fd88f0848) mio_0_8 = { package = "mio", git = "https://github.com/glandium/mio", rev = "9a2ef335c366044ffe73b1c4acabe50a1daefe05" } @@ -230,8 +227,8 @@ mio_0_8 = { package = "mio", git = "https://github.com/glandium/mio", rev = "9a2 path = "third_party/rust/mio-0.6.23" [patch."https://github.com/mozilla/uniffi-rs.git"] -uniffi = "0.27.1" -uniffi_bindgen = "0.27.1" -uniffi_build = "0.27.1" -uniffi_macros = "0.27.1" -weedle2 = "=5.0.0" +uniffi = "=0.25.3" +uniffi_bindgen = "=0.25.3" +uniffi_build = "=0.25.3" +uniffi_macros = "=0.25.3" +weedle2 = "=4.0.0" diff --git a/build/rust/goblin/Cargo.toml b/build/rust/goblin/Cargo.toml dissimilarity index 75% index 4b6ea811e97e..52e8dfe66df1 100644 --- a/build/rust/goblin/Cargo.toml +++ b/build/rust/goblin/Cargo.toml @@ -1,26 +1,11 @@ -[package] -name = "goblin" -version = "0.7.999" -edition = "2018" -license = "MIT/Apache-2.0" - -[lib] -path = "lib.rs" - -[dependencies.goblin] -version = "0.8.0" - -default-features = false - -[features] -alloc = ["goblin/alloc"] -archive = ["goblin/archive"] -default = ["goblin/default"] -elf32 = ["goblin/elf32"] -elf64 = ["goblin/elf64"] -endian_fd = ["goblin/endian_fd"] -mach32 = ["goblin/mach32"] -mach64 = ["goblin/mach64"] -pe32 = ["goblin/pe32"] -pe64 = ["goblin/pe64"] -std = ["goblin/std"] +[package] +name = "goblin" +version = "0.6.999" +edition = "2018" +license = "MIT/Apache-2.0" + +[lib] +path = "lib.rs" + +[dependencies.goblin] +version = "0.7.0" diff --git a/build/rust/scroll/Cargo.toml b/build/rust/scroll/Cargo.toml deleted file mode 100644 index dea2c21fd1ac..000000000000 --- a/build/rust/scroll/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "scroll" -version = "0.11.999" -edition = "2018" -license = "MIT/Apache-2.0" - -[lib] -path = "lib.rs" - -[dependencies.scroll] -version = "0.12.0" -default-features = false - -[features] -default = ["scroll/default"] -derive = ["scroll/derive"] -std = ["scroll/std"] diff --git a/build/rust/scroll/lib.rs b/build/rust/scroll/lib.rs deleted file mode 100644 index f7d352d6d2a8..000000000000 --- a/build/rust/scroll/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use scroll::*; diff --git a/dom/chrome-webidl/UniFFI.webidl b/dom/chrome-webidl/UniFFI.webidl index 0341e4f21687..7a3f68fbbde5 100644 --- a/dom/chrome-webidl/UniFFI.webidl +++ b/dom/chrome-webidl/UniFFI.webidl @@ -35,9 +35,7 @@ typedef unsigned long long UniFFICallbackObjectHandle; // Opaque type used to represent a pointer from Rust [ChromeOnly, Exposed=Window] -interface UniFFIPointer { - UniFFIPointer clone(); -}; +interface UniFFIPointer {}; // Types that can be passed or returned from scaffolding functions // diff --git a/gfx/wr/Cargo.lock b/gfx/wr/Cargo.lock index 333aa68686bf..2bf28a1b6e82 100644 --- a/gfx/wr/Cargo.lock +++ b/gfx/wr/Cargo.lock @@ -347,7 +347,7 @@ dependencies = [ "indexmap", "strsim", "termcolor", - "textwrap 0.15.0", + "textwrap", "yaml-rust", ] @@ -996,9 +996,9 @@ dependencies = [ [[package]] name = "glean" -version = "59.0.0" +version = "58.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceede8fb9c90ba1b77fb8290d3ae7b62bfcb422ad1d6e46bae1c8af3f22f12d" +checksum = "f58388f10d013e2d12bb58e6e76983ede120789956fe827913a3d2560c66d44d" dependencies = [ "glean-core", "inherent", @@ -1009,9 +1009,9 @@ dependencies = [ [[package]] name = "glean-core" -version = "59.0.0" +version = "58.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea06a592b1395e0a16a5f4d6872f009ca7c98acc5127a8119088f1b435b5aaae" +checksum = "ed9acc46fd38c5c995a0537e76364496addace660839dc279079e5957e3c1093" dependencies = [ "android_logger", "bincode", @@ -1189,9 +1189,9 @@ dependencies = [ [[package]] name = "goblin" -version = "0.8.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07a4ffed2093b118a525b1d8f5204ae274faed5604537caf7135d0f18d9887" +checksum = "572564d6cba7d09775202c8e7eebc4d534d5ae36578ab402fb21e182a0ac9505" dependencies = [ "log", "plain", @@ -1873,9 +1873,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "oneshot-uniffi" -version = "0.1.6" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c" +checksum = "9ae4988774e7a7e6a0783d119bdc683ea8c1d01a24d4fff9b4bdc280e07bd99e" [[package]] name = "ordered-float" @@ -2338,22 +2338,22 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scroll" -version = "0.12.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" dependencies = [ "scroll_derive", ] [[package]] name = "scroll_derive" -version = "0.12.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 1.0.91", ] [[package]] @@ -2452,12 +2452,6 @@ dependencies = [ ] [[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - -[[package]] name = "smithay-client-toolkit" version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2624,17 +2618,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] -name = "textwrap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" -dependencies = [ - "smawk", - "unicode-linebreak", - "unicode-width", -] - -[[package]] name = "thiserror" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2735,12 +2718,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] name = "unicode-normalization" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2750,12 +2727,6 @@ dependencies = [ ] [[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2763,9 +2734,9 @@ checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "uniffi" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5566fae48a5cb017005bf9cd622af5236b2a203a13fb548afde3506d3c68277" +checksum = "21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f" dependencies = [ "anyhow", "uniffi_build", @@ -2775,9 +2746,9 @@ dependencies = [ [[package]] name = "uniffi_bindgen" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a77bb514bcd4bf27c9bd404d7c3f2a6a8131b957eba9c22cfeb7751c4278e09" +checksum = "fd992f2929a053829d5875af1eff2ee3d7a7001cb3b9a46cc7895f2caede6940" dependencies = [ "anyhow", "askama", @@ -2790,7 +2761,6 @@ dependencies = [ "once_cell", "paste", "serde", - "textwrap 0.16.1", "toml", "uniffi_meta", "uniffi_testing", @@ -2799,9 +2769,9 @@ dependencies = [ [[package]] name = "uniffi_build" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45cba427aeb7b3a8b54830c4c915079a7a3c62608dd03dddba1d867a8a023eb4" +checksum = "001964dd3682d600084b3aaf75acf9c3426699bc27b65e96bb32d175a31c74e9" dependencies = [ "anyhow", "camino", @@ -2810,9 +2780,9 @@ dependencies = [ [[package]] name = "uniffi_checksum_derive" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae7e5a6c33b1dec3f255f57ec0b6af0f0b2bb3021868be1d5eec7a38e2905ebc" +checksum = "55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c" dependencies = [ "quote", "syn 2.0.25", @@ -2820,9 +2790,9 @@ dependencies = [ [[package]] name = "uniffi_core" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea3eb5474d50fc149b7e4d86b9c5bd4a61dcc167f0683902bf18ae7bbb3deef" +checksum = "6121a127a3af1665cd90d12dd2b3683c2643c5103281d0fed5838324ca1fad5b" dependencies = [ "anyhow", "bytes", @@ -2836,9 +2806,9 @@ dependencies = [ [[package]] name = "uniffi_macros" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18331d35003f46f0d04047fbe4227291815b83a937a8c32bc057f990962182c4" +checksum = "11cf7a58f101fcedafa5b77ea037999b88748607f0ef3a33eaa0efc5392e92e4" dependencies = [ "bincode", "camino", @@ -2849,14 +2819,15 @@ dependencies = [ "serde", "syn 2.0.25", "toml", + "uniffi_build", "uniffi_meta", ] [[package]] name = "uniffi_meta" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7224422c4cfd181c7ca9fca2154abca4d21db962f926f270f996edd38b0c4b8" +checksum = "71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2" dependencies = [ "anyhow", "bytes", @@ -2866,9 +2837,9 @@ dependencies = [ [[package]] name = "uniffi_testing" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ce878d0bdfc288b58797044eaaedf748526c56eef3575380bb4d4b19d69eee" +checksum = "118448debffcb676ddbe8c5305fb933ab7e0123753e659a71dc4a693f8d9f23c" dependencies = [ "anyhow", "camino", @@ -2879,12 +2850,11 @@ dependencies = [ [[package]] name = "uniffi_udl" -version = "0.27.1" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c43c9ed40a8d20a5c3eae2d23031092db6b96dc8e571beb449ba9757484cea0" +checksum = "889edb7109c6078abe0e53e9b4070cf74a6b3468d141bdf5ef1bd4d1dc24a1c3" dependencies = [ "anyhow", - "textwrap 0.16.1", "uniffi_meta", "uniffi_testing", "weedle2", @@ -3171,9 +3141,9 @@ dependencies = [ [[package]] name = "weedle2" -version = "5.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +checksum = "2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741" dependencies = [ "nom 7.1.1", ] diff --git a/gfx/wr/servo-tidy.toml b/gfx/wr/servo-tidy.toml index d548c5089f26..442c407fcaa7 100644 --- a/gfx/wr/servo-tidy.toml +++ b/gfx/wr/servo-tidy.toml @@ -32,8 +32,6 @@ packages = [ # transition to syn 2 is underway. "syn", "synstructure", - # Requires an update to clap v4 - "textwrap", # Can be fixed by removing time dependency - see bug 1765324 "wasi", ] diff --git a/gfx/wr/webrender/Cargo.toml b/gfx/wr/webrender/Cargo.toml index b99404de0d28..506226becafe 100644 --- a/gfx/wr/webrender/Cargo.toml +++ b/gfx/wr/webrender/Cargo.toml @@ -52,7 +52,7 @@ svg_fmt = "0.4" tracy-rs = "0.1.2" derive_more = { version = "0.99", default-features = false, features = ["add_assign"] } etagere = "0.2.6" -glean = { version = "59.0.0", optional = true } +glean = { version = "58.1.0", optional = true } firefox-on-glean = { version = "0.1.0", optional = true } swgl = { path = "../swgl", optional = true } topological-sort = "0.1" diff --git a/gfx/wr/wr_glyph_rasterizer/Cargo.toml b/gfx/wr/wr_glyph_rasterizer/Cargo.toml index 93877277b5f3..b06cd0f08406 100644 --- a/gfx/wr/wr_glyph_rasterizer/Cargo.toml +++ b/gfx/wr/wr_glyph_rasterizer/Cargo.toml @@ -25,7 +25,7 @@ tracy-rs = "0.1.2" log = "0.4" lazy_static = "1" fxhash = "0.2.1" -glean = { version = "59.0.0", optional = true } +glean = { version = "58.1.0", optional = true } firefox-on-glean = { version = "0.1.0", optional = true } serde = { optional = true, version = "1.0", features = ["serde_derive"] } diff --git a/mobile/android/android-components/plugins/dependencies/src/main/java/ApplicationServices.kt b/mobile/android/android-components/plugins/dependencies/src/main/java/ApplicationServices.kt index b2ae41b30405..8c5c9bbb8e13 100644 --- a/mobile/android/android-components/plugins/dependencies/src/main/java/ApplicationServices.kt +++ b/mobile/android/android-components/plugins/dependencies/src/main/java/ApplicationServices.kt @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // These lines are generated by android-components/automation/application-services-nightly-bump.py -val VERSION = "126.20240406050257" +val VERSION = "126.20240403050706" val CHANNEL = ApplicationServicesChannel.NIGHTLY object ApplicationServicesConfig { diff --git a/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt b/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt index a58ac29588c1..6a3d4c212dfc 100644 --- a/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt +++ b/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt @@ -19,7 +19,7 @@ object Versions { const val serialization = "1.6.3" const val python_envs_plugin = "0.0.31" - const val mozilla_glean = "59.0.0" + const val mozilla_glean = "58.1.0" const val junit = "4.13.2" const val robolectric = "4.11.1" diff --git a/mobile/android/android-components/plugins/dependencies/src/main/java/moz.yaml b/mobile/android/android-components/plugins/dependencies/src/main/java/moz.yaml index 30a2f17e8fd0..419624bc0cec 100644 --- a/mobile/android/android-components/plugins/dependencies/src/main/java/moz.yaml +++ b/mobile/android/android-components/plugins/dependencies/src/main/java/moz.yaml @@ -31,11 +31,11 @@ origin: # Human-readable identifier for this version/release # Generally "version NNN", "tag SSS", "bookmark SSS" - release: e95b9ea3e839169f8818975e52ec572e57934189 (2024-04-06T05:02:57). + release: 63ea14408b4199fd0f28c56d67056ca3297a8763 (2024-04-03T05:07:06). # Revision to pull in # Must be a long or short commit SHA (long preferred) - revision: e95b9ea3e839169f8818975e52ec572e57934189 + revision: 63ea14408b4199fd0f28c56d67056ca3297a8763 # The package's license, where possible using the mnemonic from # https://spdx.org/licenses/ diff --git a/python/sites/mach.txt b/python/sites/mach.txt index 90d6f153fc99..e1cb8f159c06 100644 --- a/python/sites/mach.txt +++ b/python/sites/mach.txt @@ -93,7 +93,7 @@ vendored:third_party/python/wheel vendored:third_party/python/zipp # glean-sdk may not be installable if a wheel isn't available # and it has to be built from source. -pypi-optional:glean-sdk==59.0.0:telemetry will not be collected +pypi-optional:glean-sdk==58.1.0:telemetry will not be collected # Mach gracefully handles the case where `psutil` is unavailable. # We aren't (yet) able to pin packages in automation, so we have to # support down to the oldest locally-installed version (5.4.2). diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index b21bde4f1024..0f9a2f75e977 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -3750,11 +3750,6 @@ who = "Mike Hommey " criteria = "safe-to-deploy" delta = "0.15.2 -> 0.16.0" -[[audits.textwrap]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -delta = "0.16.0 -> 0.16.1" - [[audits.thin-vec]] who = "Aria Beingessner " criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 73065c6c4fc2..5a47fcf5e5d1 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -226,15 +226,15 @@ user-login = "jrmuizel" user-name = "Jeff Muizelaar" [[publisher.glean]] -version = "59.0.0" -when = "2024-03-28" +version = "58.1.0" +when = "2024-03-12" user-id = 48 user-login = "badboy" user-name = "Jan-Erik Rediger" [[publisher.glean-core]] -version = "59.0.0" -when = "2024-03-28" +version = "58.1.0" +when = "2024-03-12" user-id = 48 user-login = "badboy" user-name = "Jan-Erik Rediger" @@ -602,67 +602,58 @@ user-login = "Manishearth" user-name = "Manish Goregaokar" [[publisher.uniffi]] -version = "0.27.1" -when = "2024-04-03" -user-id = 111105 -user-login = "mhammond" -user-name = "Mark Hammond" +version = "0.25.3" +when = "2023-12-07" +user-id = 127697 +user-login = "bendk" [[publisher.uniffi_bindgen]] -version = "0.27.1" -when = "2024-04-03" -user-id = 111105 -user-login = "mhammond" -user-name = "Mark Hammond" +version = "0.25.3" +when = "2023-12-07" +user-id = 127697 +user-login = "bendk" [[publisher.uniffi_build]] -version = "0.27.1" -when = "2024-04-03" -user-id = 111105 -user-login = "mhammond" -user-name = "Mark Hammond" +version = "0.25.3" +when = "2023-12-07" +user-id = 127697 +user-login = "bendk" [[publisher.uniffi_checksum_derive]] -version = "0.27.1" -when = "2024-04-03" -user-id = 111105 -user-login = "mhammond" -user-name = "Mark Hammond" +version = "0.25.3" +when = "2023-12-07" +user-id = 127697 +user-login = "bendk" [[publisher.uniffi_core]] -version = "0.27.1" -when = "2024-04-03" -user-id = 111105 -user-login = "mhammond" -user-name = "Mark Hammond" +version = "0.25.3" +when = "2023-12-07" +user-id = 127697 +user-login = "bendk" [[publisher.uniffi_macros]] -version = "0.27.1" -when = "2024-04-03" -user-id = 111105 -user-login = "mhammond" -user-name = "Mark Hammond" +version = "0.25.3" +when = "2023-12-07" +user-id = 127697 +user-login = "bendk" [[publisher.uniffi_meta]] -version = "0.27.1" -when = "2024-04-03" -user-id = 111105 -user-login = "mhammond" -user-name = "Mark Hammond" +version = "0.25.3" +when = "2023-12-07" +user-id = 127697 +user-login = "bendk" [[publisher.uniffi_testing]] -version = "0.27.1" -when = "2024-04-03" -user-id = 111105 -user-login = "mhammond" -user-name = "Mark Hammond" +version = "0.25.3" +when = "2023-12-07" +user-id = 127697 +user-login = "bendk" [[publisher.uniffi_udl]] -version = "0.27.1" -when = "2024-04-03" -user-id = 111105 -user-login = "mhammond" -user-name = "Mark Hammond" +version = "0.25.3" +when = "2023-12-07" +user-id = 127697 +user-login = "bendk" [[publisher.utf8_iter]] version = "1.0.3" @@ -693,29 +684,44 @@ user-login = "alexcrichton" user-name = "Alex Crichton" [[publisher.wasm-encoder]] +version = "0.40.0" +when = "2024-01-24" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + +[[publisher.wasm-encoder]] version = "0.201.0" when = "2024-02-27" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wasm-smith]] +version = "0.15.0" +when = "2024-01-24" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + +[[publisher.wasm-smith]] version = "0.201.0" when = "2024-02-27" user-id = 73222 user-login = "wasmtime-publish" [[publisher.wast]] +version = "70.0.1" +when = "2024-01-24" +user-id = 1 +user-login = "alexcrichton" +user-name = "Alex Crichton" + +[[publisher.wast]] version = "201.0.0" when = "2024-02-27" user-id = 73222 user-login = "wasmtime-publish" -[[publisher.weedle2]] -version = "5.0.0" -when = "2024-01-24" -user-id = 127697 -user-login = "bendk" - [[publisher.winapi-util]] version = "0.1.5" when = "2020-04-20" @@ -774,6 +780,45 @@ start = "2020-01-14" end = "2024-04-27" notes = "I am an author of this crate" +[[audits.bytecode-alliance.wildcard-audits.wasm-encoder]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +user-id = 1 # Alex Crichton (alexcrichton) +start = "2020-12-11" +end = "2024-04-14" +notes = """ +This is a Bytecode Alliance authored crate maintained in the `wasm-tools` +repository of which I'm one of the primary maintainers and publishers for. +I am employed by a member of the Bytecode Alliance and plan to continue doing +so and will actively maintain this crate over time. +""" + +[[audits.bytecode-alliance.wildcard-audits.wasm-smith]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +user-id = 1 # Alex Crichton (alexcrichton) +start = "2020-09-03" +end = "2024-04-14" +notes = """ +This is a Bytecode Alliance authored crate maintained in the `wasm-tools` +repository of which I'm one of the primary maintainers and publishers for. +I am employed by a member of the Bytecode Alliance and plan to continue doing +so and will actively maintain this crate over time. +""" + +[[audits.bytecode-alliance.wildcard-audits.wast]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +user-id = 1 # Alex Crichton (alexcrichton) +start = "2019-10-16" +end = "2024-04-14" +notes = """ +This is a Bytecode Alliance authored crate maintained in the `wasm-tools` +repository of which I'm one of the primary maintainers and publishers for. +I am employed by a member of the Bytecode Alliance and plan to continue doing +so and will actively maintain this crate over time. +""" + [[audits.bytecode-alliance.audits.adler]] who = "Alex Crichton " criteria = "safe-to-deploy" @@ -828,6 +873,12 @@ who = "Benjamin Bouvier " criteria = "safe-to-deploy" delta = "0.9.0 -> 0.10.2" +[[audits.bytecode-alliance.audits.bumpalo]] +who = "Nick Fitzgerald " +criteria = "safe-to-deploy" +version = "3.11.1" +notes = "I am the author of this crate." + [[audits.bytecode-alliance.audits.cargo-platform]] who = "Pat Hickey " criteria = "safe-to-deploy" @@ -1284,20 +1335,6 @@ criteria = "safe-to-run" version = "0.2.3" aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" -[[audits.google.audits.unicode-linebreak]] -who = "Lukasz Anforowicz " -criteria = "safe-to-deploy" -version = "0.1.5" -notes = """ -Grepped for `-i cipher`, `-i crypto`, `'\bfs\b'``, `'\bnet\b'``, `'\bunsafe\b'`` -and there were no hits. - -Version `0.1.2` of this crate has been added to Chromium in -https://source.chromium.org/chromium/chromium/src/+/591a0f30c5eac93b6a3d981c2714ffa4db28dbcb -The CL description contains a link to a Google-internal document with audit details. -""" -aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT" - [[audits.google.audits.version_check]] who = "George Burgess IV " criteria = "safe-to-deploy" @@ -1403,87 +1440,6 @@ who = "Brandon Pitman " criteria = "safe-to-deploy" delta = "0.10.7 -> 0.10.8" -[[audits.mozilla.wildcard-audits.uniffi]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 111105 # Mark Hammond (mhammond) -start = "2021-11-22" -end = "2024-11-28" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.uniffi_bindgen]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 111105 # Mark Hammond (mhammond) -start = "2021-11-22" -end = "2024-11-28" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.uniffi_build]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 111105 # Mark Hammond (mhammond) -start = "2021-11-22" -end = "2024-11-28" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.uniffi_checksum_derive]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 111105 # Mark Hammond (mhammond) -start = "2023-11-20" -end = "2024-11-28" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.uniffi_core]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 111105 # Mark Hammond (mhammond) -start = "2023-11-20" -end = "2024-11-28" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.uniffi_macros]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 111105 # Mark Hammond (mhammond) -start = "2021-11-22" -end = "2024-11-28" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.uniffi_meta]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 111105 # Mark Hammond (mhammond) -start = "2023-11-20" -end = "2024-11-28" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.uniffi_testing]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 111105 # Mark Hammond (mhammond) -start = "2023-11-20" -end = "2024-11-28" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.uniffi_udl]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 111105 # Mark Hammond (mhammond) -start = "2023-11-20" -end = "2024-11-28" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.wildcard-audits.weedle2]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -user-id = 127697 # bendk -start = "2022-06-16" -end = "2025-03-05" -notes = "Maintained by Mozilla" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - [[audits.mozilla.wildcard-audits.zeitstempel]] who = "Jan-Erik Rediger " criteria = "safe-to-deploy" @@ -1531,13 +1487,6 @@ no unsafe code. """ aggregated-from = "https://raw.githubusercontent.com/mozilla/cargo-vet/main/supply-chain/audits.toml" -[[audits.mozilla.audits.goblin]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -delta = "0.7.1 -> 0.8.0" -notes = "MSRV bump, no unsafe changes" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - [[audits.mozilla.audits.lazy_static]] who = "Nika Layzell " criteria = "safe-to-deploy" @@ -1559,40 +1508,9 @@ delta = "0.4.18 -> 0.4.20" notes = "Only cfg attribute and internal macro changes and module refactorings" aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" -[[audits.mozilla.audits.oneshot-uniffi]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -delta = "0.1.5 -> 0.1.6" -notes = "Synced with the orginal crate, no new unsafe" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - [[audits.mozilla.audits.rkv]] who = "Kagami Sascha Rosylight " criteria = "safe-to-deploy" delta = "0.18.4 -> 0.19.0" notes = "Maintained by Mozilla, no addition of unsafe blocks" aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.audits.scroll]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -delta = "0.11.0 -> 0.12.0" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.audits.scroll_derive]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -delta = "0.11.1 -> 0.12.0" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.audits.smawk]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -version = "0.3.2" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" - -[[audits.mozilla.audits.textwrap]] -who = "Jan-Erik Rediger " -criteria = "safe-to-deploy" -version = "0.15.0" -aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml" diff --git a/third_party/rust/error-support/.cargo-checksum.json b/third_party/rust/error-support/.cargo-checksum.json index e81ad5191109..475bff76658f 100644 --- a/third_party/rust/error-support/.cargo-checksum.json +++ b/third_party/rust/error-support/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"bd2f0908b3576a3ad9a416ecb0e4f8441a48a95036cf0439a65e37d836178142","README.md":"8030b4a314b1be31ba018ac12c3b586bb736db5307c3c395f2857fffe0130322","build.rs":"c8d3c38c1208eea36224662b284d8daf3e7ad1b07d22d750524f3da1cc66ccca","src/errorsupport.udl":"e793034d01a2608298528051757f38405e006ee1abc4cf65dc6f18c53590ace8","src/handling.rs":"6e0568b18d426531cb2ae9967c8dd0d51ece5a065f68b15eeb308b995edaa167","src/lib.rs":"96ae3cc2c1077ae45442ace6b5b5311b86267d0b9067f3ff58396af30ccbbc07","src/macros.rs":"0d03f82fab20c96a182f941baf3fcf2a286b00fea871ee7fd8e339abc14f9522","src/redact.rs":"c9a4df1a87be68b15d583587bda941d4c60a1d0449e2d43ff99f3611a290a863","src/reporting.rs":"38efd24d86ba8facfb181cb27e8b698d2831db0afab85691ffda034a4dc68dfa","uniffi.toml":"644fe81c12fe3c01ee81e017ca3c00d0e611f014b7eade51aadaf208179a3450"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"49ef90bd388b59229db34b35fe06eb769183431c88b5712e6e9992851aef605d","README.md":"8030b4a314b1be31ba018ac12c3b586bb736db5307c3c395f2857fffe0130322","build.rs":"c8d3c38c1208eea36224662b284d8daf3e7ad1b07d22d750524f3da1cc66ccca","src/errorsupport.udl":"e793034d01a2608298528051757f38405e006ee1abc4cf65dc6f18c53590ace8","src/handling.rs":"6e0568b18d426531cb2ae9967c8dd0d51ece5a065f68b15eeb308b995edaa167","src/lib.rs":"96ae3cc2c1077ae45442ace6b5b5311b86267d0b9067f3ff58396af30ccbbc07","src/macros.rs":"0d03f82fab20c96a182f941baf3fcf2a286b00fea871ee7fd8e339abc14f9522","src/redact.rs":"c9a4df1a87be68b15d583587bda941d4c60a1d0449e2d43ff99f3611a290a863","src/reporting.rs":"38efd24d86ba8facfb181cb27e8b698d2831db0afab85691ffda034a4dc68dfa","uniffi.toml":"644fe81c12fe3c01ee81e017ca3c00d0e611f014b7eade51aadaf208179a3450"},"package":null} \ No newline at end of file diff --git a/third_party/rust/error-support/Cargo.toml b/third_party/rust/error-support/Cargo.toml index 074ad4a32d94..e4c39618a64a 100644 --- a/third_party/rust/error-support/Cargo.toml +++ b/third_party/rust/error-support/Cargo.toml @@ -21,7 +21,7 @@ license = "MPL-2.0" [dependencies] log = "0.4" -uniffi = "0.27.1" +uniffi = "0.25.2" [dependencies.backtrace] version = "0.3" @@ -37,5 +37,5 @@ version = "1.4" version = ">=0.11,<=0.12" [build-dependencies.uniffi] -version = "0.27.1" +version = "0.25.2" features = ["build"] diff --git a/third_party/rust/glean-core/.cargo-checksum.json b/third_party/rust/glean-core/.cargo-checksum.json index 663b3141c3ae..54674fc7681a 100644 --- a/third_party/rust/glean-core/.cargo-checksum.json +++ b/third_party/rust/glean-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c590a29d01f2ccad65fdbed80578177ae3c02522d6c6c60eef9644d71f04a0e3","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"026495898699b54608eb4ec16074ffafc57920d80ccb59961c501a1ea28c9985","build.rs":"4857bea99c6b8c08db8818efa9d3738716f52d3acb68159323957ae52892a3eb","src/common_metric_data.rs":"864990a1e5770d5d5fdebcd2c36b58c3442334030fb60f53811395b56baac94b","src/core/mod.rs":"9880520967e9da0b475d280c17cd70debf9a1d15912018cbba775e5fde0ff588","src/core_metrics.rs":"a877e42e0f8b932adb52a5681ad76fd977808cb48c7eeb29b1e4bbe804f1ea96","src/coverage.rs":"49613fd310bd24d779472720975fbe6c97ec370a95eb55f10afa43f67539c942","src/database/mod.rs":"b3684bb6a11e0aa2a51306a53feddbc89bc21879d4930d5e9995869950af3413","src/debug.rs":"d0dfc0932a0953bbbe029f723bf2613c8d691f34b017e858030c46b02a46a17d","src/dispatcher/global.rs":"f69cd81a90a37c306d4e0ce8177ea5a3ae2ffda5b431ae46b9a22c9e38891271","src/dispatcher/mod.rs":"391310269947452d7e0de24c848c183110c60149d75e345ba6d5d146f222dace","src/error.rs":"b93c7d3e243b21bb9eafc95f17860aba1a942b2f2b0a7f43307690f05fece516","src/error_recording.rs":"1aba34e9d3c741755055f5b76415114b25b146b0aa90049c3457cfe12066deda","src/event_database/mod.rs":"78633293e1f3c9e9d51705615a7a4b603d7f85567bfdc2b0bad35ccda6a12d44","src/fd_logger.rs":"0c9def6fa53db1a2ab93c85795f8a7df57797bcfd3978146923e151752e291a6","src/glean.udl":"0fcf72a8e3304d98e896dd3dfd9787208776c2b21b59f1c241029978ee37a925","src/glean_metrics.rs":"9414fb1453d19f6832df33e4c6ef7383d62203e47026bf5bc9552b083101ddd1","src/histogram/exponential.rs":"58bb1770bae45770d92995515d328eb50a7e78726224f779446ae7d1632a6a3e","src/histogram/functional.rs":"1a63a305b48bcef7bc38136b40d916df4bb8f098dc602514ada54a9b091f6951","src/histogram/linear.rs":"4342a1733175d7f97b2b41adb18100537c206100c9fccb5bd13bd782c9cb3c9a","src/histogram/mod.rs":"bbb9535a633b5a85b6b11c6e4eed3314ab797950355a9bb8ccf3a22000f1e093","src/internal_metrics.rs":"263779535963a804c8c7fa6f8e284ac8ec7f415ceeadbb6a8f913a1e7073ae18","src/internal_pings.rs":"0e3b8ce673cf92bd085fd4f07aa43876c97472dbd921a2d0dc0f10c9fe6b1c6b","src/lib.rs":"fb50a72a7221358c5daa1a8c0e59c92d5d358adc10b1ba9b831d2f07c07d90e2","src/lib_unit_tests.rs":"76d1997f7608b735cc4e905cfa94f79dd71a4a2ed1eccaa89d3d72ccd8d348e2","src/metrics/boolean.rs":"2b9ef57e3582c9bd8b2cca8ab94c962a4871ecc00e837b913c9b0349ba9dff08","src/metrics/counter.rs":"b4a52a8167fb0edd6354f952525e59f3eadb4261de3483374f03c94449d30b92","src/metrics/custom_distribution.rs":"e1f2edfefb67da4bf369bab3d3047f4ff6539a1fea0eee81c78d96626e5b4bb0","src/metrics/datetime.rs":"e4405762fc71718299fa1b208e3d5fda654bd1b82fe908c884c284e3530de2ec","src/metrics/denominator.rs":"95e8442f90bad97f80fc74b146782f215344b52c5f3825ae0a8baffdc001a714","src/metrics/event.rs":"cd52e200d313e2e6f31707419d4a7fe1cab34916ee145f8136440d6da34aaad4","src/metrics/experiment.rs":"5f9278cca4e133eb8df33bbfe36d1fe0ef3eade8c09f1b46db3c4d0790515412","src/metrics/labeled.rs":"8d6e76a07064d132cd617c7901f2bc11ff6ba31e3483ba3b96354a4a3736b58d","src/metrics/memory_distribution.rs":"7f6ca51acb470df277ff14427c0e7bb07d921c0a0087d0cc56aebe038d198ccc","src/metrics/memory_unit.rs":"ee32e020cb303dd631457374048a3ed53a2e7cbacc29c54d17d836fb15507538","src/metrics/metrics_enabled_config.rs":"c45f2cd48b36f8706e0e1d402d6fc375f5bab50f7d0840e0fbbbeacb6f2732af","src/metrics/mod.rs":"8f8958b8cedfe01df6c97ec26b63f14fd7516f9de7ba62984062db96b5708720","src/metrics/numerator.rs":"937dfd583b797ac798a525cedca95c5a36262356760a89670d8113983c263154","src/metrics/object.rs":"89ce5190ed681b26b74a06a4ecaf9f96c36f96be1276f1fdb40f4406648e08c1","src/metrics/ping.rs":"86dc577422075c759edb998acbd890c239569d72b30a994e7777d6d0f7676c5a","src/metrics/quantity.rs":"aa13a8f8cf8e5e0281668fbbafc2998411df2a499479423558fd91b9bd7f8702","src/metrics/rate.rs":"603cc45c149c7a27c93b6a80146bf43f8ce70d9655f905bb5be6bc2c15bcb22b","src/metrics/recorded_experiment.rs":"33958abee79d8b55dec4cb5d20742640423713010f76314075cefde18b5c118a","src/metrics/string.rs":"0906b4d5ec1ec10b7a56fd6eb39dc30500531658df2c8bc3f55c9579e15c88db","src/metrics/string_list.rs":"ed53a095184c3e8224d0511809b5d7601ba3166505a39b0570f24ebeb0a5b97c","src/metrics/text.rs":"757f6919124d74e0512faa5bb9751a729b6bbc63ebe4d16ca81e9087f5595eaf","src/metrics/time_unit.rs":"4704703e19e799933aec3f39e3d3a125058756d7c7ba04f8729885c7843df447","src/metrics/timespan.rs":"1ad5233c7522cab70b4c095fb24cace66ace9741731f97bc001ede071f10d1ef","src/metrics/timing_distribution.rs":"261f971d012e80e93180caea69da549498597d47771264c9bb0667a9573f47ed","src/metrics/url.rs":"589ae1f8047367ad8c19b57a48ca8130d5f36cf3ce5954124150f0eb89c620ea","src/metrics/uuid.rs":"cacffd95ab30ed327ec2fa5feaf1359e667706746401f1e2c1195ad9553c4b54","src/ping/mod.rs":"fcadd52d2d536c9ace01f8a3812c3fb3c39b8094915db1b3656839fb87f771b5","src/scheduler.rs":"129863e31205404a3d1708627a62583324c347d143f976216f769893ec541ea0","src/storage/mod.rs":"91f02556f113799e0d88d732ab342bda443f43461369e8b41c424c074d742591","src/system.rs":"e3d1b54e1d39cafe6f4dc7ff5021b08c879733f909951b0e1332b3efa9ed97bd","src/traits/boolean.rs":"be0e130f8043215705becc956d45b126c340568f1b24a396c0af9b4334a41ced","src/traits/counter.rs":"c686d26e131d854cd7a7df83c900ca7c17a03c663a30cf58ab48c7259476ce85","src/traits/custom_distribution.rs":"0bd1d425e4c059cca6af2dfb13c78e5e4c6c07fb46c7e31489ad0c5959854833","src/traits/datetime.rs":"636ac1456b1b042e38cf5ae6193c5b232ea0b80df62f583a2097891baef9641b","src/traits/event.rs":"a02235aae630aba7a45a3166b756927252b397af3ecdfab7236931e62725ac49","src/traits/labeled.rs":"c633c68e70a44e73f8aff88aaab1029c0faded3cad08d822590ed8838f24b4fd","src/traits/memory_distribution.rs":"55bb8f45e948319fbba9d28a50d8742da134b066a42e480887db7c7e435f4096","src/traits/mod.rs":"d14b69d0946848c1f92cc8977cbc3fc9338ff1b53b7acc31ea0fe2f1122beecb","src/traits/numerator.rs":"6e4f236bdc448f1bde7a8c249dcd086204c2c69990d3f444e746290929226ed3","src/traits/object.rs":"c03bad670ec7affbc578247f9e1904e898c1870b9bf25750c5094113f995623f","src/traits/ping.rs":"8831c106c03afeb458b0b028fa1ce61f056ebf8e82bc0a171a1bff255d920748","src/traits/quantity.rs":"6ffe25c913bef4315573d747308c182de740b2a4e02ba22cd21d0c33ba521f31","src/traits/rate.rs":"f000790440e0f389f0b160526a9a9a266e58d1405915ae56ac550f482858222c","src/traits/string.rs":"0c3c88382ff2e8eba89c7cfe129c4b84e31140af717819533c14919541ad790c","src/traits/string_list.rs":"14e56b62c2c2be1dd8013f12001f235b084abd2a0d5aa2f7932843877af49ac0","src/traits/text.rs":"8af7d3a0c87cfd8c6d33d6ad47532b431055bbdd395f9110da5630222c23cf93","src/traits/timespan.rs":"52be325a9c061916f34c5b638a07a93b4a14aa89fe365783103d2e06b998f547","src/traits/timing_distribution.rs":"00ebdef647a7a208c01d13ba7b3996750e36de98d1f63859b609c80c8df25b6f","src/traits/url.rs":"c27f7add23214ff051078b65b88120b620560d2841a1056c7214d5237e86b9e4","src/traits/uuid.rs":"81322e71c7e847bacaf827a2cd58f6193bdc208355524207f7f38db039da6aa8","src/upload/directory.rs":"e42c62f27ace5c6504cc7703a4c1d9ffd0e6ac7c4fba7d7dee231430fb67f8f8","src/upload/mod.rs":"6151a6d3b4fccb3df7ef03207e2f77bf34dbf04b3b705e2af55dd02a731f99f8","src/upload/policy.rs":"c250957a37783e74af8002cd80ba06ef9780a389fb0f61b8b665b79688f0a360","src/upload/request.rs":"5891364d4254aafdb43751f476b0b908b681544793ac98802fe103de321ec326","src/upload/result.rs":"7efbbe50e8d36beb3f23e7bfd172d22e1c003472d2dd8055b06f6050c36437c5","src/util.rs":"ee7500434d9758a320dd410f18d7e18da956591e19d2555db87eef9623e4b916","tests/boolean.rs":"76d6014ff108cb6514d9bceb1b2b14749a55b09921f4595a5e30f1bd3546e9f0","tests/common/mod.rs":"c5bf5a9f3660ae1a1c1dbb659ab6be60438c58bc7c459f2f96dca467d05d4ab3","tests/counter.rs":"3663a3f5ec5c0bd2b758a9920cd20cc619a12566b445e4421ec7c98232bf5a32","tests/custom_distribution.rs":"41c593a0b4561e21f29d1a5b948de964a866253c58ca76ffefebe370fca150e0","tests/datetime.rs":"ec3c9760e70bb2cbc61ab23281c891bc1ec493c5c545466c29fd13e4f05c2c96","tests/event.rs":"0fbec0e8929c99603b79c62a1f57f8cabe614451fdafb6eb9d47f22116303245","tests/labeled.rs":"e9ea6dba17059d68114efce0c23373be9ceed922bf5e638a2158a6422c75a1c1","tests/memory_distribution.rs":"a5a7aa955e60823ea29a6f4bc96c61e41f1e41f08958aa4854668cf8fe04cde6","tests/object.rs":"8c35676e04f6ccf54a28764700915e753fc0355bfa5d7804d72caba66fd564cd","tests/ping.rs":"eb9f6be1aba21acc5dc670622bf622976718a706df1cc2095efa56a8e8b3fe1a","tests/ping_maker.rs":"7ad1f76a1eda2dabf0422fff74d9c2c1a39b9d1d315a4dbe6057dff44efcfae0","tests/quantity.rs":"55e7dca346fd1d27f0974b78ca3fb12427cb5da2ee637afc08a54f360f947361","tests/rate.rs":"1de571b9f0ee9a9006cbc8a31f91352d3ff1190b50840f0f668b470a7cd2a3a5","tests/storage.rs":"f0c8312bd789d7bda502cd45f35fef6b8591652bd194d07da4d81935ebe69b48","tests/string.rs":"7ece988a4b8efe6932ccb90bfe2f3c8aaea983777e99d7de6028bf6a29459ee6","tests/string_list.rs":"77188a2b90663c3f8dac5da89a6cb6b1d16a9f8c66ccd032d02966dfd14a3486","tests/text.rs":"1d43f6b90a43124311cacf0a6ee16f9e1e9263bcd11fee8b996d6efd81633638","tests/timespan.rs":"d50d75c7d75da3a878d67331cb0df8ae5e6a099ffab474361f71a408e02528d7","tests/timing_distribution.rs":"20860a7baccdcee6aed40c9cc8202b94f3b2e61164fbaf8f2af96b0f404a895a","tests/uuid.rs":"052ad26a6927c56272219340211cf4a059d200f14287b482fe8621d7bce3cc54","uniffi.toml":"6ddc98b686b0925a81abd9d1c769e5c98ac29771b210a1c535931a46dec9a8e3"},"package":"ea06a592b1395e0a16a5f4d6872f009ca7c98acc5127a8119088f1b435b5aaae"} \ No newline at end of file +{"files":{"Cargo.toml":"2dde200f0e0e4e523634f8c2c8c1c2ca75af83163ac7b0ba8f62f3096fd0c97d","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"026495898699b54608eb4ec16074ffafc57920d80ccb59961c501a1ea28c9985","build.rs":"4857bea99c6b8c08db8818efa9d3738716f52d3acb68159323957ae52892a3eb","src/common_metric_data.rs":"72051c4349885d4a94fc41bb4edda88d31551f2f9ebcdb4e868a98161bc76233","src/core/mod.rs":"8f5e98a108ec5d1849402af1de90b5f53ba839240743c2c5283a49a4045e1293","src/core_metrics.rs":"a877e42e0f8b932adb52a5681ad76fd977808cb48c7eeb29b1e4bbe804f1ea96","src/coverage.rs":"49613fd310bd24d779472720975fbe6c97ec370a95eb55f10afa43f67539c942","src/database/mod.rs":"3917bad7773696a43ab58e7860d5a8f1d63dca7c27920343aa8786acc5a586cd","src/debug.rs":"90158cc5d488ba67b60d06647e54e59a1d7bdeb906087e4fe4cfab4373c1cc6c","src/dispatcher/global.rs":"f69cd81a90a37c306d4e0ce8177ea5a3ae2ffda5b431ae46b9a22c9e38891271","src/dispatcher/mod.rs":"440a331a7beeaa6e9824c2fd4306c09ce2a115a358d5beb830dba4d69aec3563","src/error.rs":"b93c7d3e243b21bb9eafc95f17860aba1a942b2f2b0a7f43307690f05fece516","src/error_recording.rs":"d7858647808d81173558e12de88f3fbe4e589969e3bd246bfb388f90f8ff3814","src/event_database/mod.rs":"9d4d3e4b075dc585c00317304401b2c9115f39db8fdbd9f1c93d3fc6fd350fd5","src/fd_logger.rs":"0c9def6fa53db1a2ab93c85795f8a7df57797bcfd3978146923e151752e291a6","src/glean.udl":"24d9e431f95d79dc4254feff68f19a4ea4e6e76c33b110e10c5e5dbd5bc64ff2","src/glean_metrics.rs":"9414fb1453d19f6832df33e4c6ef7383d62203e47026bf5bc9552b083101ddd1","src/histogram/exponential.rs":"58bb1770bae45770d92995515d328eb50a7e78726224f779446ae7d1632a6a3e","src/histogram/functional.rs":"1a63a305b48bcef7bc38136b40d916df4bb8f098dc602514ada54a9b091f6951","src/histogram/linear.rs":"4342a1733175d7f97b2b41adb18100537c206100c9fccb5bd13bd782c9cb3c9a","src/histogram/mod.rs":"eeb7aff80806ab76cdce101dc08887b5552f8b4bdf64683f64f767e0f06a889d","src/internal_metrics.rs":"263779535963a804c8c7fa6f8e284ac8ec7f415ceeadbb6a8f913a1e7073ae18","src/internal_pings.rs":"7267166a8e357053526c545cf62bb502a7b6f07aed1de48d43041228d8835366","src/lib.rs":"367ea21f9d3f1c808b258011821d8505cd47d29eff8e8e6d938623e6e9997b73","src/lib_unit_tests.rs":"46897c6bb4003c5e00152d7b55c00d3176b5bffb28d8669a3fb0d10e5233e3a5","src/metrics/boolean.rs":"2b9ef57e3582c9bd8b2cca8ab94c962a4871ecc00e837b913c9b0349ba9dff08","src/metrics/counter.rs":"b4a52a8167fb0edd6354f952525e59f3eadb4261de3483374f03c94449d30b92","src/metrics/custom_distribution.rs":"e1f2edfefb67da4bf369bab3d3047f4ff6539a1fea0eee81c78d96626e5b4bb0","src/metrics/datetime.rs":"e4405762fc71718299fa1b208e3d5fda654bd1b82fe908c884c284e3530de2ec","src/metrics/denominator.rs":"95e8442f90bad97f80fc74b146782f215344b52c5f3825ae0a8baffdc001a714","src/metrics/event.rs":"7281d8b63f34758a47abd7ae3956f44701d1fd48433ccba7a4302526a9912255","src/metrics/experiment.rs":"5f9278cca4e133eb8df33bbfe36d1fe0ef3eade8c09f1b46db3c4d0790515412","src/metrics/labeled.rs":"8d6e76a07064d132cd617c7901f2bc11ff6ba31e3483ba3b96354a4a3736b58d","src/metrics/memory_distribution.rs":"7f6ca51acb470df277ff14427c0e7bb07d921c0a0087d0cc56aebe038d198ccc","src/metrics/memory_unit.rs":"d7a678e5242febd021283b30c0099a9e62729944816a3f17d2d91e2808bc0570","src/metrics/metrics_enabled_config.rs":"87fed12219c756ecf1e5c8cd6a21f26999b6bbcf3ffc1b5467b0a58ca5ad35d8","src/metrics/mod.rs":"8f8958b8cedfe01df6c97ec26b63f14fd7516f9de7ba62984062db96b5708720","src/metrics/numerator.rs":"937dfd583b797ac798a525cedca95c5a36262356760a89670d8113983c263154","src/metrics/object.rs":"89ce5190ed681b26b74a06a4ecaf9f96c36f96be1276f1fdb40f4406648e08c1","src/metrics/ping.rs":"4ccdf0ae2ac6f3e5a352334797d2805f1a3d932e92f08447285dd9bec4e7d724","src/metrics/quantity.rs":"aa13a8f8cf8e5e0281668fbbafc2998411df2a499479423558fd91b9bd7f8702","src/metrics/rate.rs":"603cc45c149c7a27c93b6a80146bf43f8ce70d9655f905bb5be6bc2c15bcb22b","src/metrics/recorded_experiment.rs":"33958abee79d8b55dec4cb5d20742640423713010f76314075cefde18b5c118a","src/metrics/string.rs":"2418632c492463970c3eca533d5318f519698bb361d73dd8781db108d7d1fbd8","src/metrics/string_list.rs":"ed53a095184c3e8224d0511809b5d7601ba3166505a39b0570f24ebeb0a5b97c","src/metrics/text.rs":"5c994a282b16b9dde6d6dc4922475457a72c82f64248778811b84db70ed4c116","src/metrics/time_unit.rs":"b7578010c6270a45b30342b59189a862b2ede9dd24e9afae3e90fa6b970b3d24","src/metrics/timespan.rs":"b0fda3a45597c8306a0d1928dcf0837538859e66ebd9db113ebb6efbea721d4c","src/metrics/timing_distribution.rs":"5da04272dd8b44502ffd0b60b12c84239a7fe359a51754b6c0cd96388a4e8a3c","src/metrics/url.rs":"f6b27a60d13a1268f0115c5d292c9b16b6bc370055961368cb2648283b7140a0","src/metrics/uuid.rs":"cacffd95ab30ed327ec2fa5feaf1359e667706746401f1e2c1195ad9553c4b54","src/ping/mod.rs":"fcadd52d2d536c9ace01f8a3812c3fb3c39b8094915db1b3656839fb87f771b5","src/scheduler.rs":"129863e31205404a3d1708627a62583324c347d143f976216f769893ec541ea0","src/storage/mod.rs":"04dc1a94be1d59097cd87b14386952a6ec8b9115bc06397ae389a323f6f55dcc","src/system.rs":"e3d1b54e1d39cafe6f4dc7ff5021b08c879733f909951b0e1332b3efa9ed97bd","src/traits/boolean.rs":"be0e130f8043215705becc956d45b126c340568f1b24a396c0af9b4334a41ced","src/traits/counter.rs":"c686d26e131d854cd7a7df83c900ca7c17a03c663a30cf58ab48c7259476ce85","src/traits/custom_distribution.rs":"0bd1d425e4c059cca6af2dfb13c78e5e4c6c07fb46c7e31489ad0c5959854833","src/traits/datetime.rs":"636ac1456b1b042e38cf5ae6193c5b232ea0b80df62f583a2097891baef9641b","src/traits/event.rs":"3f48aa336854141784d121f7fa9e283f6ff708a9214f9c0aade3a68cc38dda99","src/traits/labeled.rs":"c633c68e70a44e73f8aff88aaab1029c0faded3cad08d822590ed8838f24b4fd","src/traits/memory_distribution.rs":"55bb8f45e948319fbba9d28a50d8742da134b066a42e480887db7c7e435f4096","src/traits/mod.rs":"d14b69d0946848c1f92cc8977cbc3fc9338ff1b53b7acc31ea0fe2f1122beecb","src/traits/numerator.rs":"6e4f236bdc448f1bde7a8c249dcd086204c2c69990d3f444e746290929226ed3","src/traits/object.rs":"c03bad670ec7affbc578247f9e1904e898c1870b9bf25750c5094113f995623f","src/traits/ping.rs":"8831c106c03afeb458b0b028fa1ce61f056ebf8e82bc0a171a1bff255d920748","src/traits/quantity.rs":"6ffe25c913bef4315573d747308c182de740b2a4e02ba22cd21d0c33ba521f31","src/traits/rate.rs":"f000790440e0f389f0b160526a9a9a266e58d1405915ae56ac550f482858222c","src/traits/string.rs":"0c3c88382ff2e8eba89c7cfe129c4b84e31140af717819533c14919541ad790c","src/traits/string_list.rs":"14e56b62c2c2be1dd8013f12001f235b084abd2a0d5aa2f7932843877af49ac0","src/traits/text.rs":"8af7d3a0c87cfd8c6d33d6ad47532b431055bbdd395f9110da5630222c23cf93","src/traits/timespan.rs":"52be325a9c061916f34c5b638a07a93b4a14aa89fe365783103d2e06b998f547","src/traits/timing_distribution.rs":"00ebdef647a7a208c01d13ba7b3996750e36de98d1f63859b609c80c8df25b6f","src/traits/url.rs":"c27f7add23214ff051078b65b88120b620560d2841a1056c7214d5237e86b9e4","src/traits/uuid.rs":"81322e71c7e847bacaf827a2cd58f6193bdc208355524207f7f38db039da6aa8","src/upload/directory.rs":"6359220db9d85ee0f3931ca518f95ffb2020c1c03bd632f17ed5c16ddd00343b","src/upload/mod.rs":"a388563d5e2940c5c28b48fc7b67ca507512efccae95fd1c2f04b15ec21aa08c","src/upload/policy.rs":"c250957a37783e74af8002cd80ba06ef9780a389fb0f61b8b665b79688f0a360","src/upload/request.rs":"0b7e215f61499a681d1cebc9cf4a0efbaae2f543a5d44e5db40cbe61ed90549e","src/upload/result.rs":"7efbbe50e8d36beb3f23e7bfd172d22e1c003472d2dd8055b06f6050c36437c5","src/util.rs":"ee7500434d9758a320dd410f18d7e18da956591e19d2555db87eef9623e4b916","tests/boolean.rs":"76d6014ff108cb6514d9bceb1b2b14749a55b09921f4595a5e30f1bd3546e9f0","tests/common/mod.rs":"c1d980a9cff0b64f452ebbe43f24d70aa685b80b48db08fc4338a60466b07a5e","tests/counter.rs":"3663a3f5ec5c0bd2b758a9920cd20cc619a12566b445e4421ec7c98232bf5a32","tests/custom_distribution.rs":"41c593a0b4561e21f29d1a5b948de964a866253c58ca76ffefebe370fca150e0","tests/datetime.rs":"ec3c9760e70bb2cbc61ab23281c891bc1ec493c5c545466c29fd13e4f05c2c96","tests/event.rs":"67291cbcc4d1cba56ada6ba733fb1dc4c6327680059e8d7637add2ae45cd344b","tests/labeled.rs":"e9ea6dba17059d68114efce0c23373be9ceed922bf5e638a2158a6422c75a1c1","tests/memory_distribution.rs":"a5a7aa955e60823ea29a6f4bc96c61e41f1e41f08958aa4854668cf8fe04cde6","tests/object.rs":"8c35676e04f6ccf54a28764700915e753fc0355bfa5d7804d72caba66fd564cd","tests/ping.rs":"eb9f6be1aba21acc5dc670622bf622976718a706df1cc2095efa56a8e8b3fe1a","tests/ping_maker.rs":"b267ecf7c714ff27512424b743da0ea4f05a87755c1b96355bfca3e173e3f62e","tests/quantity.rs":"55e7dca346fd1d27f0974b78ca3fb12427cb5da2ee637afc08a54f360f947361","tests/rate.rs":"1de571b9f0ee9a9006cbc8a31f91352d3ff1190b50840f0f668b470a7cd2a3a5","tests/storage.rs":"f0c8312bd789d7bda502cd45f35fef6b8591652bd194d07da4d81935ebe69b48","tests/string.rs":"7ece988a4b8efe6932ccb90bfe2f3c8aaea983777e99d7de6028bf6a29459ee6","tests/string_list.rs":"77188a2b90663c3f8dac5da89a6cb6b1d16a9f8c66ccd032d02966dfd14a3486","tests/text.rs":"1d43f6b90a43124311cacf0a6ee16f9e1e9263bcd11fee8b996d6efd81633638","tests/timespan.rs":"d50d75c7d75da3a878d67331cb0df8ae5e6a099ffab474361f71a408e02528d7","tests/timing_distribution.rs":"20860a7baccdcee6aed40c9cc8202b94f3b2e61164fbaf8f2af96b0f404a895a","tests/uuid.rs":"052ad26a6927c56272219340211cf4a059d200f14287b482fe8621d7bce3cc54","uniffi.toml":"6ddc98b686b0925a81abd9d1c769e5c98ac29771b210a1c535931a46dec9a8e3"},"package":"ed9acc46fd38c5c995a0537e76364496addace660839dc279079e5957e3c1093"} \ No newline at end of file diff --git a/third_party/rust/glean-core/Cargo.toml b/third_party/rust/glean-core/Cargo.toml index 932b16a4a7c3..9d33444fbd56 100644 --- a/third_party/rust/glean-core/Cargo.toml +++ b/third_party/rust/glean-core/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.66" name = "glean-core" -version = "59.0.0" +version = "58.1.0" authors = [ "Jan-Erik Rediger ", "The Glean Team ", @@ -80,7 +80,7 @@ version = "1.0.4" version = "0.1.40" [dependencies.uniffi] -version = "0.27.0" +version = "0.25.2" default-features = false [dependencies.uuid] @@ -105,7 +105,7 @@ version = "0.4" version = "3.8.0" [build-dependencies.uniffi] -version = "0.27.0" +version = "0.25.2" features = ["build"] default-features = false diff --git a/third_party/rust/glean-core/src/common_metric_data.rs b/third_party/rust/glean-core/src/common_metric_data.rs index 9bda9bb46250..033cbe1472c3 100644 --- a/third_party/rust/glean-core/src/common_metric_data.rs +++ b/third_party/rust/glean-core/src/common_metric_data.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use std::convert::TryFrom; use std::sync::atomic::{AtomicU8, Ordering}; use crate::error::{Error, ErrorKind}; diff --git a/third_party/rust/glean-core/src/core/mod.rs b/third_party/rust/glean-core/src/core/mod.rs index f69f0c386878..30f9a34f1166 100644 --- a/third_party/rust/glean-core/src/core/mod.rs +++ b/third_party/rust/glean-core/src/core/mod.rs @@ -120,7 +120,6 @@ where /// rate_limit: None, /// enable_event_timestamps: true, /// experimentation_id: None, -/// enable_internal_pings: true, /// }; /// let mut glean = Glean::new(cfg).unwrap(); /// let ping = PingType::new("sample", true, false, true, true, vec![]); @@ -209,7 +208,7 @@ impl Glean { core_metrics: CoreMetrics::new(), additional_metrics: AdditionalMetrics::new(), database_metrics: DatabaseMetrics::new(), - internal_pings: InternalPings::new(cfg.enable_internal_pings), + internal_pings: InternalPings::new(), upload_manager, data_path: PathBuf::from(&cfg.data_path), application_id, @@ -289,9 +288,7 @@ impl Glean { } // We set this only for non-subprocess situations. - // If internal pings are disabled, we don't set up the MPS either, - // it wouldn't send any data anyway. - glean.schedule_metrics_pings = cfg.enable_internal_pings && cfg.use_core_mps; + glean.schedule_metrics_pings = cfg.use_core_mps; // We only scan the pendings pings directories **after** dealing with the upload state. // If upload is disabled, we delete all pending pings files @@ -308,7 +305,6 @@ impl Glean { data_path: &str, application_id: &str, upload_enabled: bool, - enable_internal_pings: bool, ) -> Self { let cfg = InternalConfiguration { data_path: data_path.into(), @@ -324,7 +320,6 @@ impl Glean { rate_limit: None, enable_event_timestamps: true, experimentation_id: None, - enable_internal_pings, }; let mut glean = Self::new(cfg).unwrap(); diff --git a/third_party/rust/glean-core/src/database/mod.rs b/third_party/rust/glean-core/src/database/mod.rs index 0dbf0220bcbb..af473c98d956 100644 --- a/third_party/rust/glean-core/src/database/mod.rs +++ b/third_party/rust/glean-core/src/database/mod.rs @@ -824,6 +824,7 @@ mod test { use super::*; use crate::tests::new_glean; use std::collections::HashMap; + use std::path::Path; use tempfile::tempdir; #[test] diff --git a/third_party/rust/glean-core/src/debug.rs b/third_party/rust/glean-core/src/debug.rs index 88f807bd88bb..a572a02b8f72 100644 --- a/third_party/rust/glean-core/src/debug.rs +++ b/third_party/rust/glean-core/src/debug.rs @@ -240,6 +240,7 @@ fn validate_source_tags(tags: &Vec) -> bool { #[cfg(test)] mod test { use super::*; + use std::env; #[test] fn debug_option_is_correctly_loaded_from_env() { diff --git a/third_party/rust/glean-core/src/dispatcher/mod.rs b/third_party/rust/glean-core/src/dispatcher/mod.rs index ead58fb86755..48efa4ef9606 100644 --- a/third_party/rust/glean-core/src/dispatcher/mod.rs +++ b/third_party/rust/glean-core/src/dispatcher/mod.rs @@ -360,8 +360,9 @@ impl Dispatcher { #[cfg(test)] mod test { use super::*; - use std::sync::atomic::AtomicU8; - use std::sync::Mutex; + use std::sync::atomic::{AtomicBool, AtomicU8, Ordering}; + use std::sync::{Arc, Mutex}; + use std::{thread, time::Duration}; fn enable_test_logging() { // When testing we want all logs to go to stdout/stderr by default, diff --git a/third_party/rust/glean-core/src/error_recording.rs b/third_party/rust/glean-core/src/error_recording.rs index fa828242f1b4..aaf850d019ee 100644 --- a/third_party/rust/glean-core/src/error_recording.rs +++ b/third_party/rust/glean-core/src/error_recording.rs @@ -12,6 +12,7 @@ //! but are not actually used directly, since the `send_in_pings` value needs to match the pings of the metric that is erroring (plus the "metrics" ping), //! not some constant value that we could define in `metrics.yaml`. +use std::convert::TryFrom; use std::fmt::Display; use crate::common_metric_data::CommonMetricDataInternal; diff --git a/third_party/rust/glean-core/src/event_database/mod.rs b/third_party/rust/glean-core/src/event_database/mod.rs index 50b2488a4c1c..d83e56fbec9f 100644 --- a/third_party/rust/glean-core/src/event_database/mod.rs +++ b/third_party/rust/glean-core/src/event_database/mod.rs @@ -4,6 +4,7 @@ use std::cmp::Ordering; use std::collections::HashMap; +use std::convert::TryFrom; use std::fs; use std::fs::{create_dir_all, File, OpenOptions}; use std::io::BufRead; @@ -637,8 +638,8 @@ impl EventDatabase { #[cfg(test)] mod test { use super::*; - use crate::test_get_num_recorded_errors; use crate::tests::new_glean; + use crate::{test_get_num_recorded_errors, CommonMetricData}; use chrono::{TimeZone, Timelike}; #[test] diff --git a/third_party/rust/glean-core/src/glean.udl b/third_party/rust/glean-core/src/glean.udl index dc71fea5941c..e68a57ea4ce7 100644 --- a/third_party/rust/glean-core/src/glean.udl +++ b/third_party/rust/glean-core/src/glean.udl @@ -90,7 +90,6 @@ dictionary InternalConfiguration { PingRateLimit? rate_limit; boolean enable_event_timestamps; string? experimentation_id; - boolean enable_internal_pings; }; // How to specify the rate pings may be uploaded before they are throttled. diff --git a/third_party/rust/glean-core/src/histogram/mod.rs b/third_party/rust/glean-core/src/histogram/mod.rs index 6e2880dffa32..282b02e0ab59 100644 --- a/third_party/rust/glean-core/src/histogram/mod.rs +++ b/third_party/rust/glean-core/src/histogram/mod.rs @@ -5,6 +5,7 @@ //! A simple histogram implementation for exponential histograms. use std::collections::HashMap; +use std::convert::TryFrom; use serde::{Deserialize, Serialize}; diff --git a/third_party/rust/glean-core/src/internal_pings.rs b/third_party/rust/glean-core/src/internal_pings.rs index 1cf32feb604c..07c3849006e5 100644 --- a/third_party/rust/glean-core/src/internal_pings.rs +++ b/third_party/rust/glean-core/src/internal_pings.rs @@ -19,9 +19,9 @@ pub struct InternalPings { } impl InternalPings { - pub fn new(enabled: bool) -> InternalPings { + pub fn new() -> InternalPings { InternalPings { - baseline: PingType::new_internal( + baseline: PingType::new( "baseline", true, true, @@ -32,9 +32,8 @@ impl InternalPings { "dirty_startup".to_string(), "inactive".to_string(), ], - enabled, ), - metrics: PingType::new_internal( + metrics: PingType::new( "metrics", true, false, @@ -47,9 +46,8 @@ impl InternalPings { "tomorrow".to_string(), "upgrade".to_string(), ], - enabled, ), - events: PingType::new_internal( + events: PingType::new( "events", true, false, @@ -60,7 +58,6 @@ impl InternalPings { "inactive".to_string(), "max_capacity".to_string(), ], - enabled, ), deletion_request: PingType::new( "deletion-request", diff --git a/third_party/rust/glean-core/src/lib.rs b/third_party/rust/glean-core/src/lib.rs index af68fde2648d..b7f9d73beb95 100644 --- a/third_party/rust/glean-core/src/lib.rs +++ b/third_party/rust/glean-core/src/lib.rs @@ -17,6 +17,7 @@ use std::borrow::Cow; use std::collections::HashMap; +use std::convert::TryFrom; use std::fmt; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; @@ -24,7 +25,7 @@ use std::thread; use std::time::Duration; use crossbeam_channel::unbounded; -use log::LevelFilter; +use log::{self, LevelFilter}; use once_cell::sync::{Lazy, OnceCell}; use uuid::Uuid; @@ -135,8 +136,6 @@ pub struct InternalConfiguration { /// be noted that this has an underlying StringMetric and so should conform to the limitations that /// StringMetric places on length, etc. pub experimentation_id: Option, - /// Whether to enable internal pings. Default: true - pub enable_internal_pings: bool, } /// How to specify the rate at which pings may be uploaded before they are throttled. diff --git a/third_party/rust/glean-core/src/lib_unit_tests.rs b/third_party/rust/glean-core/src/lib_unit_tests.rs index 14d3b984172b..cb1e4129d85f 100644 --- a/third_party/rust/glean-core/src/lib_unit_tests.rs +++ b/third_party/rust/glean-core/src/lib_unit_tests.rs @@ -6,10 +6,12 @@ // the lib.rs file. use std::collections::HashSet; +use std::iter::FromIterator; use serde_json::json; use super::*; +use crate::metrics::{StringMetric, TimeUnit, TimespanMetric, TimingDistributionMetric}; const GLOBAL_APPLICATION_ID: &str = "org.mozilla.glean.test.app"; pub fn new_glean(tempdir: Option) -> (Glean, tempfile::TempDir) { @@ -19,7 +21,7 @@ pub fn new_glean(tempdir: Option) -> (Glean, tempfile::TempDi None => tempfile::tempdir().unwrap(), }; let tmpname = dir.path().display().to_string(); - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); (glean, dir) } @@ -39,7 +41,7 @@ fn path_is_constructed_from_data() { fn experiment_id_and_branch_get_truncated_if_too_long() { let t = tempfile::tempdir().unwrap(); let name = t.path().display().to_string(); - let glean = Glean::with_options(&name, "org.mozilla.glean.tests", true, true); + let glean = Glean::with_options(&name, "org.mozilla.glean.tests", true); // Generate long strings for the used ids. let very_long_id = "test-experiment-id".repeat(10); @@ -80,7 +82,7 @@ fn experiment_id_and_branch_get_truncated_if_too_long() { fn limits_on_experiments_extras_are_applied_correctly() { let t = tempfile::tempdir().unwrap(); let name = t.path().display().to_string(); - let glean = Glean::with_options(&name, "org.mozilla.glean.tests", true, true); + let glean = Glean::with_options(&name, "org.mozilla.glean.tests", true); let experiment_id = "test-experiment_id".to_string(); let branch_id = "test-branch-id".to_string(); @@ -136,7 +138,7 @@ fn limits_on_experiments_extras_are_applied_correctly() { fn experiments_status_is_correctly_toggled() { let t = tempfile::tempdir().unwrap(); let name = t.path().display().to_string(); - let glean = Glean::with_options(&name, "org.mozilla.glean.tests", true, true); + let glean = Glean::with_options(&name, "org.mozilla.glean.tests", true); // Define the experiment's data. let experiment_id: String = "test-toggle-experiment".into(); @@ -197,7 +199,6 @@ fn experimentation_id_is_set_correctly() { rate_limit: None, enable_event_timestamps: true, experimentation_id: Some(experimentation_id.to_string()), - enable_internal_pings: true, }) .unwrap(); @@ -218,7 +219,7 @@ fn client_id_and_first_run_date_must_be_regenerated() { let dir = tempfile::tempdir().unwrap(); let tmpname = dir.path().display().to_string(); { - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); glean.data_store.as_ref().unwrap().clear_all(); @@ -235,7 +236,7 @@ fn client_id_and_first_run_date_must_be_regenerated() { } { - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); assert!(glean .core_metrics .client_id @@ -338,7 +339,7 @@ fn client_id_is_managed_correctly_when_toggling_uploading() { fn client_id_is_set_to_known_value_when_uploading_disabled_at_start() { let dir = tempfile::tempdir().unwrap(); let tmpname = dir.path().display().to_string(); - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, false, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, false); assert_eq!( *KNOWN_CLIENT_ID, @@ -354,7 +355,7 @@ fn client_id_is_set_to_known_value_when_uploading_disabled_at_start() { fn client_id_is_set_to_random_value_when_uploading_enabled_at_start() { let dir = tempfile::tempdir().unwrap(); let tmpname = dir.path().display().to_string(); - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); let current_client_id = glean .core_metrics @@ -368,7 +369,7 @@ fn client_id_is_set_to_random_value_when_uploading_enabled_at_start() { fn enabling_when_already_enabled_is_a_noop() { let dir = tempfile::tempdir().unwrap(); let tmpname = dir.path().display().to_string(); - let mut glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let mut glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); assert!(!glean.set_upload_enabled(true)); } @@ -377,7 +378,7 @@ fn enabling_when_already_enabled_is_a_noop() { fn disabling_when_already_disabled_is_a_noop() { let dir = tempfile::tempdir().unwrap(); let tmpname = dir.path().display().to_string(); - let mut glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, false, true); + let mut glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, false); assert!(!glean.set_upload_enabled(false)); } @@ -600,14 +601,14 @@ fn test_first_run() { let dir = tempfile::tempdir().unwrap(); let tmpname = dir.path().display().to_string(); { - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); // Check that this is indeed the first run. assert!(glean.is_first_run()); } { // Other runs must be not marked as "first run". - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); assert!(!glean.is_first_run()); } } @@ -617,7 +618,7 @@ fn test_dirty_bit() { let dir = tempfile::tempdir().unwrap(); let tmpname = dir.path().display().to_string(); { - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); // The dirty flag must not be set the first time Glean runs. assert!(!glean.is_dirty_flag_set()); @@ -629,7 +630,7 @@ fn test_dirty_bit() { { // Check that next time Glean runs, it correctly picks up the "dirty flag". // It is expected to be 'true'. - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); assert!(glean.is_dirty_flag_set()); // Set the dirty flag to false. @@ -640,7 +641,7 @@ fn test_dirty_bit() { { // Check that next time Glean runs, it correctly picks up the "dirty flag". // It is expected to be 'false'. - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); assert!(!glean.is_dirty_flag_set()); } } @@ -1064,7 +1065,7 @@ fn test_empty_application_id() { let dir = tempfile::tempdir().unwrap(); let tmpname = dir.path().display().to_string(); - let glean = Glean::with_options(&tmpname, "", true, true); + let glean = Glean::with_options(&tmpname, "", true); // Check that this is indeed the first run. assert!(glean.is_first_run()); } @@ -1079,7 +1080,7 @@ fn records_database_file_size() { let tmpname = dir.path().display().to_string(); // Initialize Glean once to ensure we create the database and did not error. - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); let database_size = &glean.database_metrics.size; let data = database_size.get_value(&glean, "metrics"); @@ -1088,7 +1089,7 @@ fn records_database_file_size() { drop(glean); // Initialize Glean again to record file size. - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, true); + let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true); let database_size = &glean.database_metrics.size; let data = database_size.get_value(&glean, "metrics"); @@ -1160,46 +1161,3 @@ fn test_activity_api() { // Check that we set everything we needed for the 'inactive' status. assert!(!glean.is_dirty_flag_set()); } - -#[test] -fn disabled_pings_are_not_submitted() { - let _ = env_logger::builder().is_test(true).try_init(); - - let dir = tempfile::tempdir().unwrap(); - let (mut glean, _t) = new_glean(Some(dir)); - - let ping = PingType::new_internal("custom-disabled", true, false, true, true, vec![], false); - glean.register_ping_type(&ping); - - // We need to store a metric as an empty ping is not stored. - let counter = CounterMetric::new(CommonMetricData { - name: "counter".into(), - category: "local".into(), - send_in_pings: vec!["custom-disabled".into()], - ..Default::default() - }); - counter.add_sync(&glean, 1); - - assert!(!ping.submit_sync(&glean, None)); -} - -#[test] -fn internal_pings_can_be_disabled() { - let _ = env_logger::builder().is_test(true).try_init(); - - let dir = tempfile::tempdir().unwrap(); - let tmpname = dir.path().display().to_string(); - let glean = Glean::with_options(&tmpname, GLOBAL_APPLICATION_ID, true, false); - - // We need to store a metric as an empty ping is not stored. - let counter = CounterMetric::new(CommonMetricData { - name: "counter".into(), - category: "local".into(), - send_in_pings: vec!["baseline".into()], - ..Default::default() - }); - counter.add_sync(&glean, 1); - - let submitted = glean.internal_pings.baseline.submit_sync(&glean, None); - assert!(!submitted); -} diff --git a/third_party/rust/glean-core/src/metrics/event.rs b/third_party/rust/glean-core/src/metrics/event.rs index 74f90f486759..c7aefd9cd643 100644 --- a/third_party/rust/glean-core/src/metrics/event.rs +++ b/third_party/rust/glean-core/src/metrics/event.rs @@ -175,21 +175,9 @@ impl EventMetric { .into() .unwrap_or_else(|| &self.meta().inner.send_in_pings[0]); - let events = glean + glean .event_storage() - .test_get_value(&self.meta, queried_ping_name); - - events.map(|mut evts| { - for ev in &mut evts { - let Some(extra) = &mut ev.extra else { continue }; - extra.remove("glean_timestamp"); - if extra.is_empty() { - ev.extra = None; - } - } - - evts - }) + .test_get_value(&self.meta, queried_ping_name) } /// **Test-only API (exported for FFI purposes).** diff --git a/third_party/rust/glean-core/src/metrics/memory_unit.rs b/third_party/rust/glean-core/src/metrics/memory_unit.rs index 19006a594e4e..ce51b975fa17 100644 --- a/third_party/rust/glean-core/src/metrics/memory_unit.rs +++ b/third_party/rust/glean-core/src/metrics/memory_unit.rs @@ -2,6 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use std::convert::TryFrom; + use serde::{Deserialize, Serialize}; use crate::error::{Error, ErrorKind}; diff --git a/third_party/rust/glean-core/src/metrics/metrics_enabled_config.rs b/third_party/rust/glean-core/src/metrics/metrics_enabled_config.rs index b36cbc150a6d..26d0deff314c 100644 --- a/third_party/rust/glean-core/src/metrics/metrics_enabled_config.rs +++ b/third_party/rust/glean-core/src/metrics/metrics_enabled_config.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::collections::HashMap; +use std::{collections::HashMap, convert::TryFrom}; use serde::{Deserialize, Serialize}; diff --git a/third_party/rust/glean-core/src/metrics/ping.rs b/third_party/rust/glean-core/src/metrics/ping.rs index 5defab7a71dc..e60284b1e25f 100644 --- a/third_party/rust/glean-core/src/metrics/ping.rs +++ b/third_party/rust/glean-core/src/metrics/ping.rs @@ -31,11 +31,6 @@ struct InnerPing { pub include_info_sections: bool, /// The "reason" codes that this ping can send pub reason_codes: Vec, - - /// Whether this ping is enabled. - /// Note: Data for disabled pings is still recorded. - /// It will not be cleared out on submit. - enabled: bool, } impl fmt::Debug for PingType { @@ -73,26 +68,6 @@ impl PingType { include_info_sections: bool, reason_codes: Vec, ) -> Self { - Self::new_internal( - name, - include_client_id, - send_if_empty, - precise_timestamps, - include_info_sections, - reason_codes, - true, - ) - } - - pub(crate) fn new_internal>( - name: A, - include_client_id: bool, - send_if_empty: bool, - precise_timestamps: bool, - include_info_sections: bool, - reason_codes: Vec, - enabled: bool, - ) -> Self { let this = Self(Arc::new(InnerPing { name: name.into(), include_client_id, @@ -100,7 +75,6 @@ impl PingType { precise_timestamps, include_info_sections, reason_codes, - enabled, })); // Register this ping. @@ -166,11 +140,6 @@ impl PingType { /// Whether the ping was succesfully assembled and queued. #[doc(hidden)] pub fn submit_sync(&self, glean: &Glean, reason: Option<&str>) -> bool { - if !self.0.enabled { - log::info!("Ping disabled: not submitting '{}' ping.", self.0.name); - return false; - } - if !glean.is_upload_enabled() { log::info!("Glean disabled: not submitting any pings."); return false; diff --git a/third_party/rust/glean-core/src/metrics/string.rs b/third_party/rust/glean-core/src/metrics/string.rs index a56ffab6486c..4aa30a8d7e06 100644 --- a/third_party/rust/glean-core/src/metrics/string.rs +++ b/third_party/rust/glean-core/src/metrics/string.rs @@ -149,8 +149,10 @@ impl StringMetric { #[cfg(test)] mod test { use super::*; + use crate::test_get_num_recorded_errors; use crate::tests::new_glean; use crate::util::truncate_string_at_boundary; + use crate::ErrorType; use crate::Lifetime; #[test] diff --git a/third_party/rust/glean-core/src/metrics/text.rs b/third_party/rust/glean-core/src/metrics/text.rs index 35f803c72854..baa8e88d7507 100644 --- a/third_party/rust/glean-core/src/metrics/text.rs +++ b/third_party/rust/glean-core/src/metrics/text.rs @@ -153,8 +153,10 @@ impl TextMetric { #[cfg(test)] mod test { use super::*; + use crate::test_get_num_recorded_errors; use crate::tests::new_glean; use crate::util::truncate_string_at_boundary; + use crate::ErrorType; use crate::Lifetime; #[test] diff --git a/third_party/rust/glean-core/src/metrics/time_unit.rs b/third_party/rust/glean-core/src/metrics/time_unit.rs index 6c68d5dff09e..6d61a8a2429a 100644 --- a/third_party/rust/glean-core/src/metrics/time_unit.rs +++ b/third_party/rust/glean-core/src/metrics/time_unit.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use std::convert::TryFrom; use std::time::Duration; use serde::{Deserialize, Serialize}; diff --git a/third_party/rust/glean-core/src/metrics/timespan.rs b/third_party/rust/glean-core/src/metrics/timespan.rs index d72492a5901a..ee63fb52f8fa 100644 --- a/third_party/rust/glean-core/src/metrics/timespan.rs +++ b/third_party/rust/glean-core/src/metrics/timespan.rs @@ -2,6 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use std::convert::TryInto; use std::sync::{Arc, RwLock}; use std::time::Duration; diff --git a/third_party/rust/glean-core/src/metrics/timing_distribution.rs b/third_party/rust/glean-core/src/metrics/timing_distribution.rs index 776935afeac5..3293be951834 100644 --- a/third_party/rust/glean-core/src/metrics/timing_distribution.rs +++ b/third_party/rust/glean-core/src/metrics/timing_distribution.rs @@ -96,7 +96,7 @@ impl TimingDistributionMetric { Self { meta: Arc::new(meta.into()), time_unit, - next_id: Arc::new(AtomicUsize::new(1)), + next_id: Arc::new(AtomicUsize::new(0)), start_times: Arc::new(Mutex::new(Default::default())), } } diff --git a/third_party/rust/glean-core/src/metrics/url.rs b/third_party/rust/glean-core/src/metrics/url.rs index 0fd5712eeba8..48b3f9e7aeca 100644 --- a/third_party/rust/glean-core/src/metrics/url.rs +++ b/third_party/rust/glean-core/src/metrics/url.rs @@ -168,7 +168,9 @@ impl UrlMetric { #[cfg(test)] mod test { use super::*; + use crate::test_get_num_recorded_errors; use crate::tests::new_glean; + use crate::ErrorType; use crate::Lifetime; #[test] diff --git a/third_party/rust/glean-core/src/storage/mod.rs b/third_party/rust/glean-core/src/storage/mod.rs index a4225e21edc8..67cb9a15526d 100644 --- a/third_party/rust/glean-core/src/storage/mod.rs +++ b/third_party/rust/glean-core/src/storage/mod.rs @@ -235,7 +235,7 @@ mod test { fn test_experiments_json_serialization() { let t = tempfile::tempdir().unwrap(); let name = t.path().display().to_string(); - let glean = Glean::with_options(&name, "org.mozilla.glean", true, true); + let glean = Glean::with_options(&name, "org.mozilla.glean", true); let extra: HashMap = [("test-key".into(), "test-value".into())] .iter() @@ -264,7 +264,7 @@ mod test { fn test_experiments_json_serialization_empty() { let t = tempfile::tempdir().unwrap(); let name = t.path().display().to_string(); - let glean = Glean::with_options(&name, "org.mozilla.glean", true, true); + let glean = Glean::with_options(&name, "org.mozilla.glean", true); let metric = ExperimentMetric::new(&glean, "some-experiment".to_string()); diff --git a/third_party/rust/glean-core/src/traits/event.rs b/third_party/rust/glean-core/src/traits/event.rs index ba8c0e56097d..aa84699b30c4 100644 --- a/third_party/rust/glean-core/src/traits/event.rs +++ b/third_party/rust/glean-core/src/traits/event.rs @@ -3,6 +3,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use std::collections::HashMap; +use std::convert::TryFrom; use std::hash::Hash; use crate::event_database::RecordedEvent; diff --git a/third_party/rust/glean-core/src/upload/directory.rs b/third_party/rust/glean-core/src/upload/directory.rs index 91a4d061d1c3..706550fe6c4e 100644 --- a/third_party/rust/glean-core/src/upload/directory.rs +++ b/third_party/rust/glean-core/src/upload/directory.rs @@ -317,6 +317,8 @@ impl PingDirectoryManager { #[cfg(test)] mod test { + use std::fs::File; + use super::*; use crate::metrics::PingType; use crate::tests::new_glean; diff --git a/third_party/rust/glean-core/src/upload/mod.rs b/third_party/rust/glean-core/src/upload/mod.rs index f217137f002f..e51a9d95086b 100644 --- a/third_party/rust/glean-core/src/upload/mod.rs +++ b/third_party/rust/glean-core/src/upload/mod.rs @@ -14,6 +14,7 @@ use std::collections::HashMap; use std::collections::VecDeque; +use std::convert::TryInto; use std::path::PathBuf; use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::sync::{Arc, RwLock, RwLockWriteGuard}; @@ -855,6 +856,9 @@ pub fn chunked_log_info(_path: &str, payload: &str) { #[cfg(test)] mod test { + use std::thread; + use std::time::Duration; + use uuid::Uuid; use super::*; diff --git a/third_party/rust/glean-core/src/upload/request.rs b/third_party/rust/glean-core/src/upload/request.rs index 6f3b0c0e5c8a..b4ac6eba9737 100644 --- a/third_party/rust/glean-core/src/upload/request.rs +++ b/third_party/rust/glean-core/src/upload/request.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; use chrono::prelude::{DateTime, Utc}; use flate2::{read::GzDecoder, write::GzEncoder, Compression}; -use serde_json::Value as JsonValue; +use serde_json::{self, Value as JsonValue}; use std::io::prelude::*; use crate::error::{ErrorKind, Result}; diff --git a/third_party/rust/glean-core/tests/common/mod.rs b/third_party/rust/glean-core/tests/common/mod.rs index cbc6201d0211..ebc4f14045aa 100644 --- a/third_party/rust/glean-core/tests/common/mod.rs +++ b/third_party/rust/glean-core/tests/common/mod.rs @@ -63,7 +63,6 @@ pub fn new_glean(tempdir: Option) -> (Glean, tempfile::TempDi rate_limit: None, enable_event_timestamps: false, experimentation_id: None, - enable_internal_pings: true, }; let glean = Glean::new(cfg).unwrap(); diff --git a/third_party/rust/glean-core/tests/event.rs b/third_party/rust/glean-core/tests/event.rs index 48120956d7d1..c83e225ca2b3 100644 --- a/third_party/rust/glean-core/tests/event.rs +++ b/third_party/rust/glean-core/tests/event.rs @@ -481,7 +481,6 @@ fn with_event_timestamps() { rate_limit: None, enable_event_timestamps: true, experimentation_id: None, // Enabling event timestamps - enable_internal_pings: true, }; let glean = Glean::new(cfg).unwrap(); diff --git a/third_party/rust/glean-core/tests/ping_maker.rs b/third_party/rust/glean-core/tests/ping_maker.rs index f716dc46921a..bc3aac63114d 100644 --- a/third_party/rust/glean-core/tests/ping_maker.rs +++ b/third_party/rust/glean-core/tests/ping_maker.rs @@ -91,7 +91,6 @@ fn test_metrics_must_report_experimentation_id() { rate_limit: None, enable_event_timestamps: true, experimentation_id: Some("test-experimentation-id".to_string()), - enable_internal_pings: true, }) .unwrap(); let ping_maker = PingMaker::new(); @@ -144,7 +143,6 @@ fn experimentation_id_is_removed_if_send_if_empty_is_false() { rate_limit: None, enable_event_timestamps: true, experimentation_id: Some("test-experimentation-id".to_string()), - enable_internal_pings: true, }) .unwrap(); let ping_maker = PingMaker::new(); diff --git a/third_party/rust/glean/.cargo-checksum.json b/third_party/rust/glean/.cargo-checksum.json index 7cb5c7390c6f..f624e73c9995 100644 --- a/third_party/rust/glean/.cargo-checksum.json +++ b/third_party/rust/glean/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"af0535de86b60e3e08cadcdb9e61ce4a699c168608d7e9e2ebb92d949e7f31ef","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"5627cc81e6187ab6c2b4dff061af16d559edcab64ba786bac39daa69c703c595","src/common_test.rs":"de47b53dcca37985c0a2b8c02daecbf32309aa54f5a4dd9290719c2c1fd0fa55","src/configuration.rs":"27075b12236021c54d0c99427bcbd417933ca02545275604d3c13f32ca25af13","src/core_metrics.rs":"fef8fb4e5fa57c179836c6eb2cf59278fe3b8b036dbe57b0ff02971b4acd822f","src/lib.rs":"d4010f265de330081467673df05bbd45efbdfeef28823f7dc11a903b11fb8976","src/net/http_uploader.rs":"01ad5bd91384411a12c74434cd1c5cd585078cb34faba4615c70bdb669a9bccb","src/net/mod.rs":"f47b96bb878f1a6c771cedbaeaeefb270bc87fb1d1bbbed1b282dddca16216ed","src/private/event.rs":"d7c70c02648584c19c73af89e5180d3c6153c911f2c6830f7d1599b18d6150eb","src/private/mod.rs":"3565eb569d2b96f938f130abe0fc3ee3f55e7e03fd6501e309d3ef6af72ef6ee","src/private/object.rs":"3f70363a196aea46cc163af025a53e48c117c6208babc4bce772bb4c337cced8","src/private/ping.rs":"a6262a3453c77cbf30766c19b535a1bf66a37b2a316e8f87baee03025255c33e","src/system.rs":"6eae5b41c15eba9cad6dbd116abe3519ee3e1fe034e79bdd692b029829a8c384","src/test.rs":"6388b9e8bf96e0fb56ad71b7a5b5630d209ae62f1a65c62e878cbc1757ddd585","tests/common/mod.rs":"08fb9483d9b6ed9fe873b4395245166ae8a15263be750c7a8e298c41d9604745","tests/init_fails.rs":"906bbf0faa613976623e0cf782bd86545b49d76afaab182af7634690b747ebf7","tests/never_init.rs":"19bad996e22f7d6958cc1a650528530aa7d1aeb4a8ab42229a90bbc0315c8ed1","tests/no_time_to_init.rs":"06c81148c27d383cb708c0c80a2e806024c9955337d7adfba8c53aaeade9be67","tests/overflowing_preinit.rs":"7ad4b2274dd9240b53430859a4eb1d2597cf508a5a678333f3d3abbadd2ed4a7","tests/persist_ping_lifetime.rs":"81415dc1d74743f02269f0d0dfa524003147056853f080276972e64a0b761d3c","tests/persist_ping_lifetime_nopanic.rs":"18379d3ffbf4a2c8c684c04ff7a0660b86dfbbb447db2d24dfed6073cb7ddf8f","tests/schema.rs":"9615eded31a2582c8f04c729d551c0c81a57029ba62a19184221c2e1cd39baf0","tests/simple.rs":"1b8b227249ae9d3cc281db07ed779bc75252c7849b1c48b4ac3d765228d65b20","tests/test-shutdown-blocking.sh":"9b16a01c190c7062474dd92182298a3d9a27928c8fa990340fdd798e6cdb7ab2","tests/test-thread-crashing.sh":"ff1bc8e5d7e4ba3a10d0d38bef222db8bfba469e7d30e45b1053d177a4084f09","tests/upload_timing.rs":"3024b7999a0c23f2c3d7e59725b5455522e4e9fdf63e3265b93fea4cec18725f"},"package":"0ceede8fb9c90ba1b77fb8290d3ae7b62bfcb422ad1d6e46bae1c8af3f22f12d"} \ No newline at end of file +{"files":{"Cargo.toml":"29b8551de6fff2f0fa3a821eb933f71a2a326b3ce3d37c25bcef3001f9146dfb","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"5627cc81e6187ab6c2b4dff061af16d559edcab64ba786bac39daa69c703c595","src/common_test.rs":"454df3d99eef045270e813946f921f56c39b16c18a5fadedc32829c3d44129cf","src/configuration.rs":"82b3a7933d913e1e2a4f328a76621db2d2e618d209d9785086d64c5c78c2a2d6","src/core_metrics.rs":"fef8fb4e5fa57c179836c6eb2cf59278fe3b8b036dbe57b0ff02971b4acd822f","src/lib.rs":"aa9c81fc6dc19ca1cb4bede25d554377a5d717fb3b246967edb1be12a395ce61","src/net/http_uploader.rs":"01ad5bd91384411a12c74434cd1c5cd585078cb34faba4615c70bdb669a9bccb","src/net/mod.rs":"f47b96bb878f1a6c771cedbaeaeefb270bc87fb1d1bbbed1b282dddca16216ed","src/private/event.rs":"d7c70c02648584c19c73af89e5180d3c6153c911f2c6830f7d1599b18d6150eb","src/private/mod.rs":"3565eb569d2b96f938f130abe0fc3ee3f55e7e03fd6501e309d3ef6af72ef6ee","src/private/object.rs":"3f70363a196aea46cc163af025a53e48c117c6208babc4bce772bb4c337cced8","src/private/ping.rs":"a6262a3453c77cbf30766c19b535a1bf66a37b2a316e8f87baee03025255c33e","src/system.rs":"6eae5b41c15eba9cad6dbd116abe3519ee3e1fe034e79bdd692b029829a8c384","src/test.rs":"6388b9e8bf96e0fb56ad71b7a5b5630d209ae62f1a65c62e878cbc1757ddd585","tests/common/mod.rs":"08fb9483d9b6ed9fe873b4395245166ae8a15263be750c7a8e298c41d9604745","tests/init_fails.rs":"906bbf0faa613976623e0cf782bd86545b49d76afaab182af7634690b747ebf7","tests/never_init.rs":"19bad996e22f7d6958cc1a650528530aa7d1aeb4a8ab42229a90bbc0315c8ed1","tests/no_time_to_init.rs":"06c81148c27d383cb708c0c80a2e806024c9955337d7adfba8c53aaeade9be67","tests/overflowing_preinit.rs":"7ad4b2274dd9240b53430859a4eb1d2597cf508a5a678333f3d3abbadd2ed4a7","tests/persist_ping_lifetime.rs":"81415dc1d74743f02269f0d0dfa524003147056853f080276972e64a0b761d3c","tests/persist_ping_lifetime_nopanic.rs":"18379d3ffbf4a2c8c684c04ff7a0660b86dfbbb447db2d24dfed6073cb7ddf8f","tests/schema.rs":"9d24028cab4dc60fe3c4d7a0bafbff0815cbc0249fa3e23625d42c3b4fa71734","tests/simple.rs":"1b8b227249ae9d3cc281db07ed779bc75252c7849b1c48b4ac3d765228d65b20","tests/test-shutdown-blocking.sh":"9b16a01c190c7062474dd92182298a3d9a27928c8fa990340fdd798e6cdb7ab2","tests/test-thread-crashing.sh":"ff1bc8e5d7e4ba3a10d0d38bef222db8bfba469e7d30e45b1053d177a4084f09","tests/upload_timing.rs":"3024b7999a0c23f2c3d7e59725b5455522e4e9fdf63e3265b93fea4cec18725f"},"package":"f58388f10d013e2d12bb58e6e76983ede120789956fe827913a3d2560c66d44d"} \ No newline at end of file diff --git a/third_party/rust/glean/Cargo.toml b/third_party/rust/glean/Cargo.toml index edcc84d5d614..bc25a0894042 100644 --- a/third_party/rust/glean/Cargo.toml +++ b/third_party/rust/glean/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.66" name = "glean" -version = "59.0.0" +version = "58.1.0" authors = [ "Jan-Erik Rediger ", "The Glean Team ", @@ -35,7 +35,7 @@ license = "MPL-2.0" repository = "https://github.com/mozilla/glean" [dependencies.glean-core] -version = "59.0.0" +version = "58.1.0" [dependencies.inherent] version = "1" diff --git a/third_party/rust/glean/src/common_test.rs b/third_party/rust/glean/src/common_test.rs index fdb7cfadbf33..e3c80da5f23c 100644 --- a/third_party/rust/glean/src/common_test.rs +++ b/third_party/rust/glean/src/common_test.rs @@ -42,6 +42,7 @@ pub(crate) fn new_glean( Some(c) => c, None => ConfigurationBuilder::new(true, tmpname, GLOBAL_APPLICATION_ID) .with_server_endpoint("invalid-test-host") + .with_event_timestamps(false) .build(), }; diff --git a/third_party/rust/glean/src/configuration.rs b/third_party/rust/glean/src/configuration.rs index 462bedaa7aed..ca0a39c3f125 100644 --- a/third_party/rust/glean/src/configuration.rs +++ b/third_party/rust/glean/src/configuration.rs @@ -46,8 +46,6 @@ pub struct Configuration { /// be noted that this has an underlying StringMetric and so should conform to the limitations that /// StringMetric places on length, etc. pub experimentation_id: Option, - /// Whether to enable internal pings. Default: true - pub enable_internal_pings: bool, } /// Configuration builder. @@ -94,8 +92,6 @@ pub struct Builder { /// be noted that this has an underlying StringMetric and so should conform to the limitations that /// StringMetric places on length, etc. pub experimentation_id: Option, - /// Whether to enable internal pings. Default: true - pub enable_internal_pings: bool, } impl Builder { @@ -119,7 +115,6 @@ impl Builder { rate_limit: None, enable_event_timestamps: true, experimentation_id: None, - enable_internal_pings: true, } } @@ -139,7 +134,6 @@ impl Builder { rate_limit: self.rate_limit, enable_event_timestamps: self.enable_event_timestamps, experimentation_id: self.experimentation_id, - enable_internal_pings: self.enable_internal_pings, } } @@ -190,10 +184,4 @@ impl Builder { self.experimentation_id = Some(value); self } - - /// Set whether to enable internal pings. - pub fn with_internal_pings(mut self, value: bool) -> Self { - self.enable_internal_pings = value; - self - } } diff --git a/third_party/rust/glean/src/lib.rs b/third_party/rust/glean/src/lib.rs index 81899d42eed5..5c5b945a957a 100644 --- a/third_party/rust/glean/src/lib.rs +++ b/third_party/rust/glean/src/lib.rs @@ -122,7 +122,6 @@ fn initialize_internal(cfg: Configuration, client_info: ClientInfoMetrics) -> Op rate_limit: cfg.rate_limit, enable_event_timestamps: cfg.enable_event_timestamps, experimentation_id: cfg.experimentation_id, - enable_internal_pings: cfg.enable_internal_pings, }; glean_core::glean_initialize(core_cfg, client_info.into(), callbacks); diff --git a/third_party/rust/glean/tests/schema.rs b/third_party/rust/glean/tests/schema.rs index 59132cd82ad8..01a2108b3c78 100644 --- a/third_party/rust/glean/tests/schema.rs +++ b/third_party/rust/glean/tests/schema.rs @@ -6,7 +6,8 @@ use std::collections::HashMap; use std::io::Read; use flate2::read::GzDecoder; -use jsonschema_valid::schemas::Draft; +use glean_core::TextMetric; +use jsonschema_valid::{self, schemas::Draft}; use serde_json::Value; use glean::net::{PingUploadRequest, UploadResult}; diff --git a/third_party/rust/goblin/.cargo-checksum.json b/third_party/rust/goblin/.cargo-checksum.json index 619a6b6211f2..4eff08bdd699 100644 --- a/third_party/rust/goblin/.cargo-checksum.json +++ b/third_party/rust/goblin/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"2d45bc2d0db50fd4416e2123f8b98c7288935b3be7985bdd115ecbd236acea41","Cargo.toml":"0d8dade295950e9f63574e7a74390ddec56c039cb44d2507df7e6ff832b49a0d","LICENSE":"036bf6b6d6fd6dd1abda2ff6cdb672a63bdf32c468048720072910f2268a965f","README.md":"302466b411dc5bc705cdf563b928c14755342ab6f2dff371be064446fa0aa0a9","src/archive/mod.rs":"ae739638d7267011bedf51712516d3485171d8f2df2ab6746a0d942d86efd6a6","src/elf/compression_header.rs":"2eb5fdda9177c1c897310d86714967de019b39c6e23b1f3a890dd3a659be0acc","src/elf/constants_header.rs":"f2ede290ecacf60b1719e9994aa45612bf0f7baf63806a293d4530a674e5861a","src/elf/constants_relocation.rs":"a010071cd2a25ab71e0c7181eb1d9f417daa2d1ec25a09c74bd12ad944892225","src/elf/dynamic.rs":"c26e75311f2da9e34dc4c0a2120dfcc20df88a41d67c52b9bf703258de018fd8","src/elf/gnu_hash.rs":"7a9fcaf6cb38167d20527364bdf9bc2379c44dede5d7666275a1eb20dc665179","src/elf/header.rs":"3391a1fa9b8e3923f7ce74caff0668d8ddb5b34767bf3da309ff497fd81c34c7","src/elf/mod.rs":"2ee0faa0917deb5e90ca60e9c852434745a4c7f553e609e9603a57b7d55b739f","src/elf/note.rs":"bf5e45e2697f7700d5adbb52f890ea4c63b70b7077ca0e7c751420bb92923529","src/elf/program_header.rs":"4c322eb124c4e2bdeec4915067d2bb11fe9e7fba1811dc351a3f7581df121da0","src/elf/reloc.rs":"a5d21f9d1ddae8e730e852fcaf1cd2dd194e35fbac8f86fb8fd9033a03bdc66d","src/elf/section_header.rs":"f55f4d263f618bd1dec76ff0483f3b2dc3791c8e5c5c2b6ff296a5bc26001666","src/elf/sym.rs":"045c01107f4e100d6827cb819b82a28ea10c0d9bc00a1cdddb04a0865f1162ec","src/elf/symver.rs":"3f899201f64a702653d44288f860003e7acd75e38111d36479af823ed92b1341","src/error.rs":"a1bb56d82db52ac627e55b163f489f06a78c939a8ccfdec210b4f726d6ed6e9d","src/lib.rs":"f29832bdf7d7f7d9e34f65704afea2710d578df60cc171dd179b5ce889faaf12","src/mach/bind_opcodes.rs":"1dcacfb853d05c2c7e6dbb4509ee705a8ea645db0d334991a2293fef92eee851","src/mach/constants.rs":"c2a2381a0b9c3047d37582465e8965d995dca414d0da21fb7bcc6b8334e49eb6","src/mach/exports.rs":"d22122744673a3ce5f54b2b4b20bfa47d17378e64d3dda2858dd13add74ed3dc","src/mach/fat.rs":"45a3228aaa1ab8b77f322dd4924b7383f1357e226ffc079846d67c0268389ea7","src/mach/header.rs":"006619188f51fa43051dc04aa4b2ecd5f89136cf05cb6a7b23a228228008e6ae","src/mach/imports.rs":"2153269dfff32e23d72f76a82d658be06bd79b7e35d79b7e17115e4eb24b13d5","src/mach/load_command.rs":"42e6f0973092185db233230e71e9312bbac7c2e1090bb6d713804020319dfa33","src/mach/mod.rs":"53ad219fd2265a5689ab38d5031722268eab6bbb649c75756e74295df4b611b7","src/mach/relocation.rs":"11b0b76ed7d997c87e396100515f931fe84473c228bed0e980fbab311530070a","src/mach/segment.rs":"0dc29bf42b25f60c7258bc8b757f6a862e846582dd6d2e70737933ad6334a0e4","src/mach/symbols.rs":"d2505fa8d65ea267abfcb6a9fc4d1acd47d5605aa6775935757e2fa8e92af507","src/pe/authenticode.rs":"ad9c77e42392b49114cf8ce2839111f3231dcfe21cbb8e402ee14e568f5ae657","src/pe/certificate_table.rs":"f6c31ba518d9fc4b6e12d2f24d6c9d58b21b341a1f189cbcf2aae0ae51304ad3","src/pe/characteristic.rs":"6f810a6e5646b922cf7e3ca6d314677a4e1e1ad5695278c2b1b527a05f4299f3","src/pe/data_directories.rs":"d0352ccc03e0ab2935235e91b391cc55828406087f026f90ec11ca5906fd8c8c","src/pe/debug.rs":"3811c616a9b6d6b54e15348bb369b794bb89532e04fe19eca91b745d7c51a553","src/pe/exception.rs":"de2c9c07812ecd315c8400fc8fdcadc6a44d7a8be96e69a3f4ccf14ef8cf8426","src/pe/export.rs":"c98f5ce0b1b18bb87f06d1d41dbf70f443d65ecb1624cb23a1ef6c5f93a892e1","src/pe/header.rs":"879c2ddc8318ab37b4577ac34241fa039d106e0e530dab07edfc9b4e13b08356","src/pe/import.rs":"855276e46c01ccd7631104e4d1265592e36c9468aadcacc937a40c29d94aabe3","src/pe/mod.rs":"ffaeca313ea2fb31c41eb0ede0ef28fede2276b0bb7d81dfc08b4ead6289600d","src/pe/optional_header.rs":"4048151649a7fe3f8f2d7bb67e784bae889eeb1651bf924f9fbe92400b809217","src/pe/options.rs":"457877197f768c331437297d787dc718b1053b813e3a1dd9b968133fb1540d44","src/pe/relocation.rs":"c479b80bb1d6910f2168505dda4f2d8925b7edc34bed4e25d069546f88f52bb3","src/pe/section_table.rs":"e4b1a2f78c2336aaa0355b5ef102dbe29138c4fa1ba29ed3f379aad1fc64bdff","src/pe/symbol.rs":"1a5fb5bec5727752a6506682ed2ab57829ea810f21f951932a0107861ec0e092","src/pe/utils.rs":"e6da9979ba5f2ae7d1274eef8230cdc4dd90c90a79c7bb9438f8b8ff0aef74be","src/strtab.rs":"dcbd0592c7f032980d112a5f752c175fe8dd257a948892e1f060d25ab52328f5","tests/bins/elf/gnu_hash/README.md":"52581e2ea7067a55bd8aedf4079200fb76448573ae9ffef7d886b9556e980db9"},"package":"bb07a4ffed2093b118a525b1d8f5204ae274faed5604537caf7135d0f18d9887"} \ No newline at end of file +{"files":{"CHANGELOG.md":"ade9f25d4bd1545f2ff2661d6a1301fe228cf2551a9cb27fcaa17c8119b73c8b","Cargo.toml":"09b271ef4ee3491cb1f6309cef8b60471b960c057c6e57fc90ed579adcc57453","LICENSE":"036bf6b6d6fd6dd1abda2ff6cdb672a63bdf32c468048720072910f2268a965f","README.md":"c09b08f3d5e7e33c4a8fd647708d313ee2ba98b165a1d077fb90f280dcb4da31","src/archive/mod.rs":"ae739638d7267011bedf51712516d3485171d8f2df2ab6746a0d942d86efd6a6","src/elf/compression_header.rs":"2eb5fdda9177c1c897310d86714967de019b39c6e23b1f3a890dd3a659be0acc","src/elf/constants_header.rs":"f2ede290ecacf60b1719e9994aa45612bf0f7baf63806a293d4530a674e5861a","src/elf/constants_relocation.rs":"a010071cd2a25ab71e0c7181eb1d9f417daa2d1ec25a09c74bd12ad944892225","src/elf/dynamic.rs":"c26e75311f2da9e34dc4c0a2120dfcc20df88a41d67c52b9bf703258de018fd8","src/elf/gnu_hash.rs":"7a9fcaf6cb38167d20527364bdf9bc2379c44dede5d7666275a1eb20dc665179","src/elf/header.rs":"3391a1fa9b8e3923f7ce74caff0668d8ddb5b34767bf3da309ff497fd81c34c7","src/elf/mod.rs":"2ee0faa0917deb5e90ca60e9c852434745a4c7f553e609e9603a57b7d55b739f","src/elf/note.rs":"bf5e45e2697f7700d5adbb52f890ea4c63b70b7077ca0e7c751420bb92923529","src/elf/program_header.rs":"4c322eb124c4e2bdeec4915067d2bb11fe9e7fba1811dc351a3f7581df121da0","src/elf/reloc.rs":"8b29162055b2846342b49e5e9e0a1482786fb92b4787bb9eb1c6d04f38b94e87","src/elf/section_header.rs":"f55f4d263f618bd1dec76ff0483f3b2dc3791c8e5c5c2b6ff296a5bc26001666","src/elf/sym.rs":"045c01107f4e100d6827cb819b82a28ea10c0d9bc00a1cdddb04a0865f1162ec","src/elf/symver.rs":"3f899201f64a702653d44288f860003e7acd75e38111d36479af823ed92b1341","src/error.rs":"af620a5692bca070dc727d49cdbb566a533bfb97724ca68932ae7fec7dc05cf6","src/lib.rs":"465eb53b540dfd142d204984ee7280130542d7f83d6c53691299d773f7394faf","src/mach/bind_opcodes.rs":"1dcacfb853d05c2c7e6dbb4509ee705a8ea645db0d334991a2293fef92eee851","src/mach/constants.rs":"c2a2381a0b9c3047d37582465e8965d995dca414d0da21fb7bcc6b8334e49eb6","src/mach/exports.rs":"d22122744673a3ce5f54b2b4b20bfa47d17378e64d3dda2858dd13add74ed3dc","src/mach/fat.rs":"45a3228aaa1ab8b77f322dd4924b7383f1357e226ffc079846d67c0268389ea7","src/mach/header.rs":"006619188f51fa43051dc04aa4b2ecd5f89136cf05cb6a7b23a228228008e6ae","src/mach/imports.rs":"2153269dfff32e23d72f76a82d658be06bd79b7e35d79b7e17115e4eb24b13d5","src/mach/load_command.rs":"0a689e774ae96212666165909c026037f22a3c4e3645250b9bae60c957d50ca4","src/mach/mod.rs":"53ad219fd2265a5689ab38d5031722268eab6bbb649c75756e74295df4b611b7","src/mach/relocation.rs":"11b0b76ed7d997c87e396100515f931fe84473c228bed0e980fbab311530070a","src/mach/segment.rs":"0dc29bf42b25f60c7258bc8b757f6a862e846582dd6d2e70737933ad6334a0e4","src/mach/symbols.rs":"d2505fa8d65ea267abfcb6a9fc4d1acd47d5605aa6775935757e2fa8e92af507","src/pe/authenticode.rs":"c3df9266c4f0a865e0da4b10fa1494eca083953fc4ded0b707b547a7d4ef296a","src/pe/certificate_table.rs":"75ab5dce6bc0c28d3687a5c119c0fa0d00e4796c8959a32d9d208f2369273c50","src/pe/characteristic.rs":"6f810a6e5646b922cf7e3ca6d314677a4e1e1ad5695278c2b1b527a05f4299f3","src/pe/data_directories.rs":"d4e156f0c5b509860ceb3c7d42e1621e6c2143b90fc412806b3cefab1acc577a","src/pe/debug.rs":"3811c616a9b6d6b54e15348bb369b794bb89532e04fe19eca91b745d7c51a553","src/pe/exception.rs":"de2c9c07812ecd315c8400fc8fdcadc6a44d7a8be96e69a3f4ccf14ef8cf8426","src/pe/export.rs":"c98f5ce0b1b18bb87f06d1d41dbf70f443d65ecb1624cb23a1ef6c5f93a892e1","src/pe/header.rs":"f02a4beddc00ddd6624df7defc42991ceb507360b5aa1003cf33332c1c89a743","src/pe/import.rs":"855276e46c01ccd7631104e4d1265592e36c9468aadcacc937a40c29d94aabe3","src/pe/mod.rs":"ec958ee9a717672dec7b56d9d7d33e444c37eb781f299a920a60eb7fa39ef7a1","src/pe/optional_header.rs":"4fd94187fb343756817f23ccc58ec035a1b462b69457c706d9e2f11225d0cb1c","src/pe/options.rs":"b38f4e87f13ae381712621786f89e931452b2b4857a7bb6f140c4c21a63aa652","src/pe/relocation.rs":"c479b80bb1d6910f2168505dda4f2d8925b7edc34bed4e25d069546f88f52bb3","src/pe/section_table.rs":"d7144c7be3242d7aa653d22dca1cf15f7110f79a946a15cbe6ecf531e0cacb19","src/pe/symbol.rs":"9a65226c93c4499e21d094ceb838d58db706951580a1c43dfb36b95dbaff70f0","src/pe/utils.rs":"88e1cd9114c5d4ad58a09c39b312689de20ddd7382654ec660b00424f5c3129c","src/strtab.rs":"6d122084cf5d5244b2bd734b1d6d2c018116cc537ffc0c81d042d5b8815d7782","tests/bins/elf/gnu_hash/README.md":"52581e2ea7067a55bd8aedf4079200fb76448573ae9ffef7d886b9556e980db9"},"package":"f27c1b4369c2cd341b5de549380158b105a04c331be5db9110eef7b6d2742134"} \ No newline at end of file diff --git a/third_party/rust/goblin/CHANGELOG.md b/third_party/rust/goblin/CHANGELOG.md index 71c79c7b4949..393105f35149 100644 --- a/third_party/rust/goblin/CHANGELOG.md +++ b/third_party/rust/goblin/CHANGELOG.md @@ -3,32 +3,9 @@ All notable changes to this project will be documented in this file. Before 1.0, this project does not adhere to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -Goblin is now 0.8, which means we will try our best to ease breaking changes. Tracking issue is here: https://github.com/m4b/goblin/issues/97 +Goblin is now 0.7, which means we will try our best to ease breaking changes. Tracking issue is here: https://github.com/m4b/goblin/issues/97 -## [0.8.0] - 2023-12-31 - Happy New Years! -### Breaking -msrv: bumped to 1.63.0 since scroll bumped as well -pe: new field added to parse options: https://github.com/m4b/goblin/pull/377 -pe: attribute certs now non-exhaustive: https://github.com/m4b/goblin/pull/378 -goblin: hint and object enum is now non-exhaustive -pe: write support introduced some breaking changes, e.g., data directories array adds a tuple of usize and data directory, - DosHeader has all the fields filled out, Header struct has a dos_stub field added, - symbols and strings fields is made optional in Coff struct, see: https://github.com/m4b/goblin/pull/361 -### Fixed -elf: fix documentation, thanks @crzysdrs: https://github.com/m4b/goblin/pull/374 -pe: attribute certificates non-exhaustive, thanks @RaitoBezarius: https://github.com/m4b/goblin/pull/378 -pe: fix authenticode parsing, thanks @baloo: https://github.com/m4b/goblin/pull/383 -### Added -strtab: len method added to return number of bytes of the strtab -pe: absolutely epic pe write support PR, thanks @RaitoBezarius and @Baloo: https://github.com/m4b/goblin/pull/361 -pe: add coff object file support, thanks @vadimcn, https://github.com/m4b/goblin/pull/379 -pe: allow toggling parsing of attribute certs, thanks @suttonbradley: https://github.com/m4b/goblin/pull/377 -mach: add new mach-o constants, thanks @keith: https://github.com/m4b/goblin/pull/372 - -## [0.7.1] - 2023-6-11 -### MSRV bump from log - -## [0.7.0] - 2023-6-11 +## [0.7.0] - unreleased ### Breaking mach: Implement `LC_NOTE`, (breakage=load commands are marked non-exhaustive), thanks @messense: https://github.com/m4b/goblin/pull/342 ### Fixed diff --git a/third_party/rust/goblin/Cargo.toml b/third_party/rust/goblin/Cargo.toml index f2d6acc38986..7c586a3e0d84 100644 --- a/third_party/rust/goblin/Cargo.toml +++ b/third_party/rust/goblin/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.63.0" +rust-version = "1.60.0" name = "goblin" -version = "0.8.0" +version = "0.7.1" authors = [ "m4b ", "seu ", @@ -44,7 +44,6 @@ categories = [ ] license = "MIT" repository = "https://github.com/m4b/goblin" -resolver = "2" [dependencies.log] version = "0.4" @@ -55,12 +54,9 @@ default-features = false version = "0.2.3" [dependencies.scroll] -version = "0.12" +version = "0.11" default_features = false -[dev-dependencies.stderrlog] -version = "0.5.4" - [features] alloc = [ "scroll/derive", diff --git a/third_party/rust/goblin/README.md b/third_party/rust/goblin/README.md index ee9462d2ffb6..76c226045727 100644 --- a/third_party/rust/goblin/README.md +++ b/third_party/rust/goblin/README.md @@ -20,13 +20,13 @@ https://docs.rs/goblin/ ### Usage -Goblin requires `rustc` 1.63.0 (Rust 2021 edition). +Goblin requires `rustc` 1.60.0 (Rust 2021 edition). Add to your `Cargo.toml` ```toml [dependencies] -goblin = "0.8" +goblin = "0.7" ``` ### Features @@ -190,7 +190,6 @@ In lexicographic order: [@baloo]: https://github.com/baloo [@burjui]: https://github.com/burjui [@connorkuehl]: https://github.com/connorkuehl -[@crzysdrs]: https://github.com/crzysdrs [@dancrossnyc]: https://github.com/dancrossnyc [@dureuill]: https://github.com/dureuill [@Evian-Zhang]: https://github.com/Evian-Zhang @@ -239,7 +238,6 @@ In lexicographic order: [@sanxiyn]: https://github.com/sanxiyn [@skdltmxn]: https://github.com/skdltmxn [@sollyucko]: https://github.com/sollyucko -[@suttonbradley]: https://github.com/suttonbradley [@Swatinem]: https://github.com/Swatinem [@SweetVishnya]: https://github.com/SweetVishnya [@SquareMan]: https://github.com/SquareMan @@ -250,7 +248,6 @@ In lexicographic order: [@Tiwalun]: https://github.com/Tiwalun [@track-5]: https://github.com/track-5 [@tux3]: https://github.com/tux3 -[@vadimcn]: https://github.com/vadimcn [@wickerwacka]: https://github.com/wickerwaka [@willglynn]: https://github.com/willglynn [@woodruffw]: https://github.com/woodruffw diff --git a/third_party/rust/goblin/src/elf/reloc.rs b/third_party/rust/goblin/src/elf/reloc.rs index d8a1df9d6a6b..eeb3e1a2ac86 100644 --- a/third_party/rust/goblin/src/elf/reloc.rs +++ b/third_party/rust/goblin/src/elf/reloc.rs @@ -51,7 +51,7 @@ //! | `R_X86_64_GOTPC32` | 26 | 32 | GOT + A - P | //! | `R_X86_64_SIZE32` | 32 | 32 | Z + A | //! | `R_X86_64_SIZE64` | 33 | 64 | Z + A | -//! | `R_X86_64_GOTPC32_TLSDESC`| 34 | 32 | | +//! | `R_X86_64_GOTPC32_TLSDESC` 34 | 32 | | //! | `R_X86_64_TLSDESC_CALL` | 35 | NONE | | //! | `R_X86_64_TLSDESC` | 36 | 64 × 2 | | //! | `R_X86_64_IRELATIVE` | 37 | 64 | indirect (B + A) | diff --git a/third_party/rust/goblin/src/error.rs b/third_party/rust/goblin/src/error.rs index 0ec4e1e0c95a..e2dd517e154e 100644 --- a/third_party/rust/goblin/src/error.rs +++ b/third_party/rust/goblin/src/error.rs @@ -3,7 +3,6 @@ use alloc::string::String; use core::fmt; -use core::num::TryFromIntError; use core::result; #[cfg(feature = "std")] use std::{error, io}; @@ -43,12 +42,6 @@ impl From for Error { } } -impl From for Error { - fn from(err: TryFromIntError) -> Error { - Error::Malformed(format!("Integer do not fit: {err}")) - } -} - impl From for Error { fn from(err: scroll::Error) -> Error { Error::Scroll(err) diff --git a/third_party/rust/goblin/src/lib.rs b/third_party/rust/goblin/src/lib.rs index ec77f93d5c26..25ab8413222e 100644 --- a/third_party/rust/goblin/src/lib.rs +++ b/third_party/rust/goblin/src/lib.rs @@ -42,17 +42,13 @@ //! Object::PE(pe) => { //! println!("pe: {:#?}", &pe); //! }, -//! Object::COFF(coff) => { -//! println!("coff: {:#?}", &coff); -//! }, //! Object::Mach(mach) => { //! println!("mach: {:#?}", &mach); //! }, //! Object::Archive(archive) => { //! println!("archive: {:#?}", &archive); //! }, -//! Object::Unknown(magic) => { println!("unknown magic: {:#x}", magic) }, -//! _ => { } +//! Object::Unknown(magic) => { println!("unknown magic: {:#x}", magic) } //! } //! } //! } @@ -222,14 +218,12 @@ pub struct HintData { } #[derive(Debug)] -#[non_exhaustive] /// A hint at the underlying binary format for 16 bytes of arbitrary data pub enum Hint { Elf(HintData), Mach(HintData), MachFat(usize), PE, - COFF, Archive, Unknown(u64), } @@ -259,14 +253,10 @@ if_everything! { Ok(Hint::Elf(HintData { is_lsb, is_64 })) } else if &bytes[0..archive::SIZEOF_MAGIC] == archive::MAGIC { Ok(Hint::Archive) + } else if (&bytes[0..2]).pread_with::(0, LE)? == pe::header::DOS_MAGIC { + Ok(Hint::PE) } else { - match *&bytes[0..2].pread_with::(0, LE)? { - pe::header::DOS_MAGIC => Ok(Hint::PE), - pe::header::COFF_MACHINE_X86 | - pe::header::COFF_MACHINE_X86_64 | - pe::header::COFF_MACHINE_ARM64 => Ok(Hint::COFF), - _ => mach::peek_bytes(bytes) - } + mach::peek_bytes(bytes) } } @@ -283,15 +273,12 @@ if_everything! { #[derive(Debug)] #[allow(clippy::large_enum_variant)] - #[non_exhaustive] /// A parseable object that goblin understands pub enum Object<'a> { /// An ELF32/ELF64! Elf(elf::Elf<'a>), /// A PE32/PE32+! PE(pe::PE<'a>), - /// A COFF - COFF(pe::Coff<'a>), /// A 32/64-bit Mach-o binary _OR_ it is a multi-architecture binary container! Mach(mach::Mach<'a>), /// A Unix archive @@ -309,8 +296,7 @@ if_everything! { Hint::Mach(_) | Hint::MachFat(_) => Ok(Object::Mach(mach::Mach::parse(bytes)?)), Hint::Archive => Ok(Object::Archive(archive::Archive::parse(bytes)?)), Hint::PE => Ok(Object::PE(pe::PE::parse(bytes)?)), - Hint::COFF => Ok(Object::COFF(pe::Coff::parse(bytes)?)), - Hint::Unknown(magic) => Ok(Object::Unknown(magic)), + Hint::Unknown(magic) => Ok(Object::Unknown(magic)) } } else { Err(error::Error::Malformed(format!("Object is too small."))) diff --git a/third_party/rust/goblin/src/mach/load_command.rs b/third_party/rust/goblin/src/mach/load_command.rs index 305c3b823f0f..34a44e2baec0 100644 --- a/third_party/rust/goblin/src/mach/load_command.rs +++ b/third_party/rust/goblin/src/mach/load_command.rs @@ -1343,12 +1343,9 @@ pub const PLATFORM_IOSSIMULATOR: u32 = 7; pub const PLATFORM_TVOSSIMULATOR: u32 = 8; pub const PLATFORM_WATCHOSSIMULATOR: u32 = 9; pub const PLATFORM_DRIVERKIT: u32 = 10; -pub const PLATFORM_VISIONOS: u32 = 11; -pub const PLATFORM_VISIONOSSIMULATOR: u32 = 12; pub const TOOL_CLANG: u32 = 1; pub const TOOL_SWIFT: u32 = 2; pub const TOOL_LD: u32 = 3; -pub const TOOL_LLD: u32 = 4; pub fn cmd_to_str(cmd: u32) -> &'static str { match cmd { diff --git a/third_party/rust/goblin/src/pe/authenticode.rs b/third_party/rust/goblin/src/pe/authenticode.rs dissimilarity index 78% index 0f738e6888bb..e16b7997cddb 100644 --- a/third_party/rust/goblin/src/pe/authenticode.rs +++ b/third_party/rust/goblin/src/pe/authenticode.rs @@ -1,278 +1,116 @@ -// Reference: -// https://learn.microsoft.com/en-us/windows-hardware/drivers/install/authenticode -// https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx - -// Authenticode works by omiting sections of the PE binary from the digest -// those sections are: -// - checksum -// - data directory entry for certtable -// - certtable - -use alloc::collections::VecDeque; -use core::ops::Range; -use log::debug; - -use super::{section_table::SectionTable, PE}; - -static PADDING: [u8; 7] = [0; 7]; - -impl PE<'_> { - /// [`authenticode_ranges`] returns the various ranges of the binary that are relevant for - /// signature. - pub fn authenticode_ranges(&self) -> ExcludedSectionsIter<'_> { - ExcludedSectionsIter { - pe: self, - state: IterState::default(), - sections: VecDeque::default(), - } - } -} - -/// [`ExcludedSections`] holds the various ranges of the binary that are expected to be -/// excluded from the authenticode computation. -#[derive(Debug, Clone, Default)] -pub(super) struct ExcludedSections { - checksum: Range, - datadir_entry_certtable: Range, - certificate_table_size: usize, - end_image_header: usize, -} - -impl ExcludedSections { - pub(super) fn new( - checksum: Range, - datadir_entry_certtable: Range, - certificate_table_size: usize, - end_image_header: usize, - ) -> Self { - Self { - checksum, - datadir_entry_certtable, - certificate_table_size, - end_image_header, - } - } -} - -pub struct ExcludedSectionsIter<'s> { - pe: &'s PE<'s>, - state: IterState, - sections: VecDeque, -} - -#[derive(Debug, PartialEq)] -enum IterState { - Initial, - ChecksumEnd(usize), - CertificateTableEnd(usize), - HeaderEnd { - end_image_header: usize, - sum_of_bytes_hashed: usize, - }, - Sections { - tail: usize, - sum_of_bytes_hashed: usize, - }, - Final { - sum_of_bytes_hashed: usize, - }, - Padding(usize), - Done, -} - -impl Default for IterState { - fn default() -> Self { - Self::Initial - } -} - -impl<'s> Iterator for ExcludedSectionsIter<'s> { - type Item = &'s [u8]; - - fn next(&mut self) -> Option { - let bytes = &self.pe.bytes; - - if let Some(sections) = self.pe.authenticode_excluded_sections.as_ref() { - loop { - match self.state { - IterState::Initial => { - // 3. Hash the image header from its base to immediately before the start of the - // checksum address, as specified in Optional Header Windows-Specific Fields. - let out = Some(&bytes[..sections.checksum.start]); - debug!("hashing {:#x} {:#x}", 0, sections.checksum.start); - - // 4. Skip over the checksum, which is a 4-byte field. - debug_assert_eq!(sections.checksum.end - sections.checksum.start, 4); - self.state = IterState::ChecksumEnd(sections.checksum.end); - - return out; - } - IterState::ChecksumEnd(checksum_end) => { - // 5. Hash everything from the end of the checksum field to immediately before the start - // of the Certificate Table entry, as specified in Optional Header Data Directories. - let out = - Some(&bytes[checksum_end..sections.datadir_entry_certtable.start]); - debug!( - "hashing {checksum_end:#x} {:#x}", - sections.datadir_entry_certtable.start - ); - - // 6. Get the Attribute Certificate Table address and size from the Certificate Table entry. - // For details, see section 5.7 of the PE/COFF specification. - // 7. Exclude the Certificate Table entry from the calculation - self.state = - IterState::CertificateTableEnd(sections.datadir_entry_certtable.end); - - return out; - } - IterState::CertificateTableEnd(start) => { - // 7. Exclude the Certificate Table entry from the calculation and hash everything from - // the end of the Certificate Table entry to the end of image header, including - // Section Table (headers). The Certificate Table entry is 8 bytes long, as specified - // in Optional Header Data Directories. - let end_image_header = sections.end_image_header; - let buf = Some(&bytes[start..end_image_header]); - debug!("hashing {start:#x} {:#x}", end_image_header - start); - - // 8. Create a counter called SUM_OF_BYTES_HASHED, which is not part of the signature. - // Set this counter to the SizeOfHeaders field, as specified in - // Optional Header Windows-Specific Field. - let sum_of_bytes_hashed = end_image_header; - - self.state = IterState::HeaderEnd { - end_image_header, - sum_of_bytes_hashed, - }; - - return buf; - } - IterState::HeaderEnd { - end_image_header, - sum_of_bytes_hashed, - } => { - // 9. Build a temporary table of pointers to all of the section headers in the - // image. The NumberOfSections field of COFF File Header indicates how big - // the table should be. Do not include any section headers in the table whose - // SizeOfRawData field is zero. - - // Implementation detail: - // We require allocation here because the section table has a variable size and - // needs to be sorted. - let mut sections: VecDeque = self - .pe - .sections - .iter() - .filter(|section| section.size_of_raw_data != 0) - .cloned() - .collect(); - - // 10. Using the PointerToRawData field (offset 20) in the referenced SectionHeader - // structure as a key, arrange the table's elements in ascending order. In - // other words, sort the section headers in ascending order according to the - // disk-file offset of the sections. - sections - .make_contiguous() - .sort_by_key(|section| section.pointer_to_raw_data); - - self.sections = sections; - - self.state = IterState::Sections { - tail: end_image_header, - sum_of_bytes_hashed, - }; - } - IterState::Sections { - mut tail, - mut sum_of_bytes_hashed, - } => { - // 11. Walk through the sorted table, load the corresponding section into memory, - // and hash the entire section. Use the SizeOfRawData field in the SectionHeader - // structure to determine the amount of data to hash. - if let Some(section) = self.sections.pop_front() { - let start = section.pointer_to_raw_data as usize; - let end = start + section.size_of_raw_data as usize; - tail = end; - - // 12. Add the section’s SizeOfRawData value to SUM_OF_BYTES_HASHED. - sum_of_bytes_hashed += section.size_of_raw_data as usize; - - debug!("hashing {start:#x} {:#x}", end - start); - let buf = &bytes[start..end]; - - // 13. Repeat steps 11 and 12 for all of the sections in the sorted table. - self.state = IterState::Sections { - tail, - sum_of_bytes_hashed, - }; - - return Some(buf); - } else { - self.state = IterState::Final { - sum_of_bytes_hashed, - }; - } - } - IterState::Final { - sum_of_bytes_hashed, - } => { - // 14. Create a value called FILE_SIZE, which is not part of the signature. - // Set this value to the image’s file size, acquired from the underlying - // file system. If FILE_SIZE is greater than SUM_OF_BYTES_HASHED, the - // file contains extra data that must be added to the hash. This data - // begins at the SUM_OF_BYTES_HASHED file offset, and its length is: - // (File Size) - ((Size of AttributeCertificateTable) + SUM_OF_BYTES_HASHED) - // - // Note: The size of Attribute Certificate Table is specified in the second - // ULONG value in the Certificate Table entry (32 bit: offset 132, - // 64 bit: offset 148) in Optional Header Data Directories. - let file_size = bytes.len(); - - // If FILE_SIZE is not a multiple of 8 bytes, the data added to the hash must - // be appended with zero padding of length (8 – (FILE_SIZE % 8)) bytes - let pad_size = (8 - file_size % 8) % 8; - self.state = IterState::Padding(pad_size); - - if file_size > sum_of_bytes_hashed { - let extra_data_start = sum_of_bytes_hashed; - let len = - file_size - sections.certificate_table_size - sum_of_bytes_hashed; - - debug!("hashing {extra_data_start:#x} {len:#x}",); - let buf = &bytes[extra_data_start..extra_data_start + len]; - - return Some(buf); - } - } - IterState::Padding(pad_size) => { - self.state = IterState::Done; - - if pad_size != 0 { - debug!("hashing {pad_size:#x}"); - - // NOTE (safety): pad size will be at most 7, and PADDING has a size of 7 - // pad_size is computed ~10 lines above. - debug_assert!(pad_size <= 7); - debug_assert_eq!(PADDING.len(), 7); - - return Some(&PADDING[..pad_size]); - } - } - IterState::Done => return None, - } - } - } else { - loop { - match self.state { - IterState::Initial => { - self.state = IterState::Done; - return Some(bytes); - } - IterState::Done => return None, - _ => { - self.state = IterState::Done; - } - } - } - } - } -} +// Reference: +// https://learn.microsoft.com/en-us/windows-hardware/drivers/install/authenticode +// https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx + +// Authenticode works by omiting sections of the PE binary from the digest +// those sections are: +// - checksum +// - data directory entry for certtable +// - certtable + +use core::ops::Range; + +use super::PE; + +impl PE<'_> { + /// [`authenticode_ranges`] returns the various ranges of the binary that are relevant for + /// signature. + pub fn authenticode_ranges(&self) -> ExcludedSectionsIter<'_> { + ExcludedSectionsIter { + pe: self, + state: IterState::default(), + } + } +} + +/// [`ExcludedSections`] holds the various ranges of the binary that are expected to be +/// excluded from the authenticode computation. +#[derive(Debug, Clone, Default)] +pub(super) struct ExcludedSections { + checksum: Range, + datadir_entry_certtable: Range, + certtable: Option>, +} + +impl ExcludedSections { + pub(super) fn new( + checksum: Range, + datadir_entry_certtable: Range, + certtable: Option>, + ) -> Self { + Self { + checksum, + datadir_entry_certtable, + certtable, + } + } +} + +pub struct ExcludedSectionsIter<'s> { + pe: &'s PE<'s>, + state: IterState, +} + +#[derive(Debug, PartialEq)] +enum IterState { + Initial, + DatadirEntry(usize), + CertTable(usize), + Final(usize), + Done, +} + +impl Default for IterState { + fn default() -> Self { + Self::Initial + } +} + +impl<'s> Iterator for ExcludedSectionsIter<'s> { + type Item = &'s [u8]; + + fn next(&mut self) -> Option { + let bytes = &self.pe.bytes; + + if let Some(sections) = self.pe.authenticode_excluded_sections.as_ref() { + loop { + match self.state { + IterState::Initial => { + self.state = IterState::DatadirEntry(sections.checksum.end); + return Some(&bytes[..sections.checksum.start]); + } + IterState::DatadirEntry(start) => { + self.state = IterState::CertTable(sections.datadir_entry_certtable.end); + return Some(&bytes[start..sections.datadir_entry_certtable.start]); + } + IterState::CertTable(start) => { + if let Some(certtable) = sections.certtable.as_ref() { + self.state = IterState::Final(certtable.end); + return Some(&bytes[start..certtable.start]); + } else { + self.state = IterState::Final(start) + } + } + IterState::Final(start) => { + self.state = IterState::Done; + return Some(&bytes[start..]); + } + IterState::Done => return None, + } + } + } else { + loop { + match self.state { + IterState::Initial => { + self.state = IterState::Done; + return Some(bytes); + } + IterState::Done => return None, + _ => { + self.state = IterState::Done; + } + } + } + } + } +} diff --git a/third_party/rust/goblin/src/pe/certificate_table.rs b/third_party/rust/goblin/src/pe/certificate_table.rs index be45ce48dcef..353a6c70ce32 100644 --- a/third_party/rust/goblin/src/pe/certificate_table.rs +++ b/third_party/rust/goblin/src/pe/certificate_table.rs @@ -3,15 +3,12 @@ /// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-attribute-certificate-table-image-only /// https://learn.microsoft.com/en-us/windows/win32/api/wintrust/ns-wintrust-win_certificate use crate::error; -use scroll::{ctx, Pread, Pwrite}; +use scroll::Pread; use alloc::string::ToString; use alloc::vec::Vec; -use super::utils::pad; - #[repr(u16)] -#[non_exhaustive] #[derive(Debug, PartialEq, Copy, Clone)] pub enum AttributeCertificateRevision { /// WIN_CERT_REVISION_1_0 @@ -41,7 +38,7 @@ impl TryFrom for AttributeCertificateRevision { } #[repr(u16)] -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug)] pub enum AttributeCertificateType { /// WIN_CERT_TYPE_X509 X509 = 0x0001, @@ -130,28 +127,7 @@ impl<'a> AttributeCertificate<'a> { } } -impl<'a> ctx::TryIntoCtx for &AttributeCertificate<'a> { - type Error = error::Error; - - /// Writes an aligned attribute certificate in the buffer. - fn try_into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) -> Result { - let offset = &mut 0; - bytes.gwrite_with(self.length, offset, ctx)?; - bytes.gwrite_with(self.revision as u16, offset, ctx)?; - bytes.gwrite_with(self.certificate_type as u16, offset, ctx)?; - // Extend by zero the buffer until it is aligned on a quadword (16 bytes). - let maybe_certificate_padding = pad(self.certificate.len(), Some(16usize)); - bytes.gwrite(self.certificate, offset)?; - if let Some(cert_padding) = maybe_certificate_padding { - bytes.gwrite(&cert_padding[..], offset)?; - } - - Ok(*offset) - } -} - pub type CertificateDirectoryTable<'a> = Vec>; - pub(crate) fn enumerate_certificates( bytes: &[u8], table_virtual_address: u32, diff --git a/third_party/rust/goblin/src/pe/data_directories.rs b/third_party/rust/goblin/src/pe/data_directories.rs dissimilarity index 75% index e65db5953d7a..265e4e27f7be 100644 --- a/third_party/rust/goblin/src/pe/data_directories.rs +++ b/third_party/rust/goblin/src/pe/data_directories.rs @@ -1,153 +1,106 @@ -use crate::error; -use scroll::{ - ctx::{self}, - Pread, Pwrite, SizeWith, -}; - -#[repr(C)] -#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] -pub struct DataDirectory { - pub virtual_address: u32, - pub size: u32, -} - -pub const SIZEOF_DATA_DIRECTORY: usize = 8; -const NUM_DATA_DIRECTORIES: usize = 16; - -impl DataDirectory { - pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result { - Ok(bytes.gread_with(offset, scroll::LE)?) - } -} - -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum DataDirectoryType { - ExportTable, - ImportTable, - ResourceTable, - ExceptionTable, - CertificateTable, - BaseRelocationTable, - DebugTable, - Architecture, - GlobalPtr, - TlsTable, - LoadConfigTable, - BoundImportTable, - ImportAddressTable, - DelayImportDescriptor, - ClrRuntimeHeader, -} - -impl TryFrom for DataDirectoryType { - type Error = error::Error; - fn try_from(value: usize) -> Result { - Ok(match value { - 0 => Self::ExportTable, - 1 => Self::ImportTable, - 2 => Self::ResourceTable, - 3 => Self::ExceptionTable, - 4 => Self::CertificateTable, - 5 => Self::BaseRelocationTable, - 6 => Self::DebugTable, - 7 => Self::Architecture, - 8 => Self::GlobalPtr, - 9 => Self::TlsTable, - 10 => Self::LoadConfigTable, - 11 => Self::BoundImportTable, - 12 => Self::ImportAddressTable, - 13 => Self::DelayImportDescriptor, - 14 => Self::ClrRuntimeHeader, - _ => { - return Err(error::Error::Malformed( - "Wrong data directory index number".into(), - )) - } - }) - } -} - -#[derive(Debug, PartialEq, Copy, Clone, Default)] -pub struct DataDirectories { - pub data_directories: [Option<(usize, DataDirectory)>; NUM_DATA_DIRECTORIES], -} - -impl ctx::TryIntoCtx for DataDirectories { - type Error = error::Error; - - fn try_into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) -> Result { - let offset = &mut 0; - for opt_dd in self.data_directories { - if let Some((dd_offset, dd)) = opt_dd { - bytes.pwrite_with(dd, dd_offset, ctx)?; - *offset += dd_offset; - } else { - bytes.gwrite(&[0; SIZEOF_DATA_DIRECTORY][..], offset)?; - } - } - Ok(NUM_DATA_DIRECTORIES * SIZEOF_DATA_DIRECTORY) - } -} - -macro_rules! build_dd_getter { - ($dd_name:tt, $index:tt) => { - pub fn $dd_name(&self) -> Option<&DataDirectory> { - let idx = $index; - self.data_directories[idx].as_ref().map(|(_, dd)| dd) - } - }; -} - -impl DataDirectories { - pub fn parse(bytes: &[u8], count: usize, offset: &mut usize) -> error::Result { - let mut data_directories = [None; NUM_DATA_DIRECTORIES]; - if count > NUM_DATA_DIRECTORIES { - return Err(error::Error::Malformed(format!( - "data directory count ({}) is greater than maximum number of data directories ({})", - count, NUM_DATA_DIRECTORIES - ))); - } - for dir in data_directories.iter_mut().take(count) { - let dd = DataDirectory::parse(bytes, offset)?; - let dd = if dd.virtual_address == 0 && dd.size == 0 { - None - } else { - Some((*offset, dd)) - }; - *dir = dd; - } - Ok(DataDirectories { data_directories }) - } - - build_dd_getter!(get_export_table, 0); - build_dd_getter!(get_import_table, 1); - build_dd_getter!(get_resource_table, 2); - build_dd_getter!(get_exception_table, 3); - build_dd_getter!(get_certificate_table, 4); - build_dd_getter!(get_base_relocation_table, 5); - build_dd_getter!(get_debug_table, 6); - build_dd_getter!(get_architecture, 7); - build_dd_getter!(get_global_ptr, 8); - build_dd_getter!(get_tls_table, 9); - build_dd_getter!(get_load_config_table, 10); - build_dd_getter!(get_bound_import_table, 11); - build_dd_getter!(get_import_address_table, 12); - build_dd_getter!(get_delay_import_descriptor, 13); - build_dd_getter!(get_clr_runtime_header, 14); - - pub fn dirs(&self) -> impl Iterator { - self.data_directories - .into_iter() - .enumerate() - // (Index, Option
) -> Option<(Index, DD)> -> (DDT, DD) - .filter_map(|(i, o)| - // We should not have invalid indexes. - // Indeed: `data_directories: &[_; N]` where N is the number - // of data directories. - // The `TryFrom` trait for integers to DataDirectoryType - // takes into account the N possible data directories. - // Therefore, the unwrap can never fail as long as Rust guarantees - // on types are honored. - o.map(|(_, v)| (i.try_into().unwrap(), v))) - } -} +use crate::error; +use scroll::{Pread, Pwrite, SizeWith}; + +#[repr(C)] +#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] +pub struct DataDirectory { + pub virtual_address: u32, + pub size: u32, +} + +pub const SIZEOF_DATA_DIRECTORY: usize = 8; +const NUM_DATA_DIRECTORIES: usize = 16; + +impl DataDirectory { + pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result { + let dd = bytes.gread_with(offset, scroll::LE)?; + Ok(dd) + } +} + +#[derive(Debug, PartialEq, Copy, Clone, Default)] +pub struct DataDirectories { + pub data_directories: [Option; NUM_DATA_DIRECTORIES], +} + +impl DataDirectories { + pub fn parse(bytes: &[u8], count: usize, offset: &mut usize) -> error::Result { + let mut data_directories = [None; NUM_DATA_DIRECTORIES]; + if count > NUM_DATA_DIRECTORIES { + return Err(error::Error::Malformed(format!( + "data directory count ({}) is greater than maximum number of data directories ({})", + count, NUM_DATA_DIRECTORIES + ))); + } + for dir in data_directories.iter_mut().take(count) { + let dd = DataDirectory::parse(bytes, offset)?; + let dd = if dd.virtual_address == 0 && dd.size == 0 { + None + } else { + Some(dd) + }; + *dir = dd; + } + Ok(DataDirectories { data_directories }) + } + pub fn get_export_table(&self) -> &Option { + let idx = 0; + &self.data_directories[idx] + } + pub fn get_import_table(&self) -> &Option { + let idx = 1; + &self.data_directories[idx] + } + pub fn get_resource_table(&self) -> &Option { + let idx = 2; + &self.data_directories[idx] + } + pub fn get_exception_table(&self) -> &Option { + let idx = 3; + &self.data_directories[idx] + } + pub fn get_certificate_table(&self) -> &Option { + let idx = 4; + &self.data_directories[idx] + } + pub fn get_base_relocation_table(&self) -> &Option { + let idx = 5; + &self.data_directories[idx] + } + pub fn get_debug_table(&self) -> &Option { + let idx = 6; + &self.data_directories[idx] + } + pub fn get_architecture(&self) -> &Option { + let idx = 7; + &self.data_directories[idx] + } + pub fn get_global_ptr(&self) -> &Option { + let idx = 8; + &self.data_directories[idx] + } + pub fn get_tls_table(&self) -> &Option { + let idx = 9; + &self.data_directories[idx] + } + pub fn get_load_config_table(&self) -> &Option { + let idx = 10; + &self.data_directories[idx] + } + pub fn get_bound_import_table(&self) -> &Option { + let idx = 11; + &self.data_directories[idx] + } + pub fn get_import_address_table(&self) -> &Option { + let idx = 12; + &self.data_directories[idx] + } + pub fn get_delay_import_descriptor(&self) -> &Option { + let idx = 13; + &self.data_directories[idx] + } + pub fn get_clr_runtime_header(&self) -> &Option { + let idx = 14; + &self.data_directories[idx] + } +} diff --git a/third_party/rust/goblin/src/pe/header.rs b/third_party/rust/goblin/src/pe/header.rs index 06e23c0b037e..c1ded9dd9ff7 100644 --- a/third_party/rust/goblin/src/pe/header.rs +++ b/third_party/rust/goblin/src/pe/header.rs @@ -3,60 +3,24 @@ use crate::pe::{optional_header, section_table, symbol}; use crate::strtab; use alloc::vec::Vec; use log::debug; -use scroll::{ctx, IOread, IOwrite, Pread, Pwrite, SizeWith}; +use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith}; /// DOS header present in all PE binaries #[repr(C)] -#[derive(Debug, PartialEq, Copy, Clone, Default, Pwrite)] +#[derive(Debug, PartialEq, Copy, Clone, Default)] pub struct DosHeader { /// Magic number: 5a4d pub signature: u16, - /// e_cblp - pub bytes_on_last_page: u16, - /// e_cp - pub pages_in_file: u16, - /// e_crlc - pub relocations: u16, - /// e_cparhdr - pub size_of_header_in_paragraphs: u16, - /// e_minalloc - pub minimum_extra_paragraphs_needed: u16, - /// e_maxalloc - pub maximum_extra_paragraphs_needed: u16, - /// e_ss - pub initial_relative_ss: u16, - /// e_sp - pub initial_sp: u16, - /// e_csum - pub checksum: u16, - /// e_ip - pub initial_ip: u16, - /// e_cs - pub initial_relative_cs: u16, - /// e_lfarlc - pub file_address_of_relocation_table: u16, - /// e_ovno - pub overlay_number: u16, - /// e_res[4] - pub reserved: [u16; 4], - /// e_oemid - pub oem_id: u16, - /// e_oeminfo - pub oem_info: u16, - /// e_res2[10] - pub reserved2: [u16; 10], - /// e_lfanew: pointer to PE header, always at offset 0x3c + /// Pointer to PE header, always at offset 0x3c pub pe_pointer: u32, } pub const DOS_MAGIC: u16 = 0x5a4d; pub const PE_POINTER_OFFSET: u32 = 0x3c; -pub const DOS_STUB_OFFSET: u32 = PE_POINTER_OFFSET + (core::mem::size_of::() as u32); impl DosHeader { pub fn parse(bytes: &[u8]) -> error::Result { - let mut offset = 0; - let signature = bytes.gread_with(&mut offset, scroll::LE).map_err(|_| { + let signature = bytes.pread_with(0, scroll::LE).map_err(|_| { error::Error::Malformed(format!("cannot parse DOS signature (offset {:#x})", 0)) })?; if signature != DOS_MAGIC { @@ -65,33 +29,6 @@ impl DosHeader { signature ))); } - - let bytes_on_last_page = bytes.gread_with(&mut offset, scroll::LE)?; - let pages_in_file = bytes.gread_with(&mut offset, scroll::LE)?; - let relocations = bytes.gread_with(&mut offset, scroll::LE)?; - let size_of_header_in_paragraphs = bytes.gread_with(&mut offset, scroll::LE)?; - let minimum_extra_paragraphs_needed = bytes.gread_with(&mut offset, scroll::LE)?; - let maximum_extra_paragraphs_needed = bytes.gread_with(&mut offset, scroll::LE)?; - let initial_relative_ss = bytes.gread_with(&mut offset, scroll::LE)?; - let initial_sp = bytes.gread_with(&mut offset, scroll::LE)?; - let checksum = bytes.gread_with(&mut offset, scroll::LE)?; - let initial_ip = bytes.gread_with(&mut offset, scroll::LE)?; - let initial_relative_cs = bytes.gread_with(&mut offset, scroll::LE)?; - let file_address_of_relocation_table = bytes.gread_with(&mut offset, scroll::LE)?; - let overlay_number = bytes.gread_with(&mut offset, scroll::LE)?; - let reserved = [0x0; 4]; - offset += core::mem::size_of_val(&reserved); - let oem_id = bytes.gread_with(&mut offset, scroll::LE)?; - let oem_info = bytes.gread_with(&mut offset, scroll::LE)?; - let reserved2 = [0x0; 10]; - offset += core::mem::size_of_val(&reserved2); - - debug_assert!( - offset == PE_POINTER_OFFSET as usize, - "expected offset ({:#x}) after reading DOS header to be at 0x3C", - offset - ); - let pe_pointer = bytes .pread_with(PE_POINTER_OFFSET as usize, scroll::LE) .map_err(|_| { @@ -100,7 +37,6 @@ impl DosHeader { PE_POINTER_OFFSET )) })?; - let pe_signature: u32 = bytes .pread_with(pe_pointer as usize, scroll::LE) @@ -116,48 +52,13 @@ impl DosHeader { pe_signature ))); } - Ok(DosHeader { signature, - bytes_on_last_page, - pages_in_file, - relocations, - size_of_header_in_paragraphs, - minimum_extra_paragraphs_needed, - maximum_extra_paragraphs_needed, - initial_relative_ss, - initial_sp, - checksum, - initial_ip, - initial_relative_cs, - file_address_of_relocation_table, - overlay_number, - reserved, - oem_id, - oem_info, - reserved2, pe_pointer, }) } } -#[repr(C)] -#[derive(Debug, PartialEq, Copy, Clone, Pread, Pwrite)] -/// The DOS stub program which should be executed in DOS mode -pub struct DosStub(pub [u8; 0x40]); -impl Default for DosStub { - fn default() -> Self { - // "This program cannot be run in DOS mode" error program - Self([ - 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, - 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, - 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, - 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]) - } -} - /// COFF Header #[repr(C)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, IOread, IOwrite, SizeWith)] @@ -262,24 +163,14 @@ impl CoffHeader { } /// Return the COFF symbol table. - pub fn symbols<'a>(&self, bytes: &'a [u8]) -> error::Result>> { + pub fn symbols<'a>(&self, bytes: &'a [u8]) -> error::Result> { let offset = self.pointer_to_symbol_table as usize; let number = self.number_of_symbol_table as usize; - if offset == 0 { - Ok(None) - } else { - symbol::SymbolTable::parse(bytes, offset, number).map(Some) - } + symbol::SymbolTable::parse(bytes, offset, number) } /// Return the COFF string table. - pub fn strings<'a>(&self, bytes: &'a [u8]) -> error::Result>> { - // > The file offset of the COFF symbol table, or zero if no COFF symbol table is present. - // > This value should be zero for an image because COFF debugging information is deprecated. - if self.pointer_to_symbol_table == 0 { - return Ok(None); - } - + pub fn strings<'a>(&self, bytes: &'a [u8]) -> error::Result> { let mut offset = self.pointer_to_symbol_table as usize + symbol::SymbolTable::size(self.number_of_symbol_table as usize); @@ -289,15 +180,13 @@ impl CoffHeader { // The offset needs to be advanced in order to read the strings. offset += length_field_size; - Ok(Some(strtab::Strtab::parse(bytes, offset, length, 0)?)) + Ok(strtab::Strtab::parse(bytes, offset, length, 0)?) } } #[derive(Debug, PartialEq, Copy, Clone, Default)] pub struct Header { pub dos_header: DosHeader, - /// DOS program for legacy loaders - pub dos_stub: DosStub, /// PE Magic: PE\0\0, little endian pub signature: u32, pub coff_header: CoffHeader, @@ -307,12 +196,6 @@ pub struct Header { impl Header { pub fn parse(bytes: &[u8]) -> error::Result { let dos_header = DosHeader::parse(&bytes)?; - let dos_stub = bytes.pread(DOS_STUB_OFFSET as usize).map_err(|_| { - error::Error::Malformed(format!( - "cannot parse DOS stub (offset {:#x})", - DOS_STUB_OFFSET - )) - })?; let mut offset = dos_header.pe_pointer as usize; let signature = bytes.gread_with(&mut offset, scroll::LE).map_err(|_| { error::Error::Malformed(format!("cannot parse PE signature (offset {:#x})", offset)) @@ -325,7 +208,6 @@ impl Header { }; Ok(Header { dos_header, - dos_stub, signature, coff_header, optional_header, @@ -333,22 +215,6 @@ impl Header { } } -impl ctx::TryIntoCtx for Header { - type Error = error::Error; - - fn try_into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) -> Result { - let offset = &mut 0; - bytes.gwrite_with(self.dos_header, offset, ctx)?; - bytes.gwrite_with(self.dos_stub, offset, ctx)?; - bytes.gwrite_with(self.signature, offset, scroll::LE)?; - bytes.gwrite_with(self.coff_header, offset, ctx)?; - if let Some(opt_header) = self.optional_header { - bytes.gwrite_with(opt_header, offset, ctx)?; - } - Ok(*offset) - } -} - /// Convert machine to str representation pub fn machine_to_str(machine: u16) -> &'static str { match machine { diff --git a/third_party/rust/goblin/src/pe/mod.rs b/third_party/rust/goblin/src/pe/mod.rs index 2336fddc570d..5a7337630a5d 100644 --- a/third_party/rust/goblin/src/pe/mod.rs +++ b/third_party/rust/goblin/src/pe/mod.rs @@ -3,12 +3,7 @@ // TODO: panics with unwrap on None for apisetschema.dll, fhuxgraphics.dll and some others -use core::cmp::max; - -use alloc::borrow::Cow; -use alloc::string::String; use alloc::vec::Vec; -use log::warn; pub mod authenticode; pub mod certificate_table; @@ -28,11 +23,8 @@ pub mod utils; use crate::container; use crate::error; -use crate::pe::utils::pad; use crate::strtab; -use scroll::{ctx, Pwrite}; - use log::debug; #[derive(Debug)] @@ -148,7 +140,7 @@ impl<'a> PE<'a> { entry, image_base, is_64 ); let file_alignment = optional_header.windows_fields.file_alignment; - if let Some(&export_table) = optional_header.data_directories.get_export_table() { + if let Some(export_table) = *optional_header.data_directories.get_export_table() { if let Ok(ed) = export::ExportData::parse_with_opts( bytes, export_table, @@ -170,7 +162,7 @@ impl<'a> PE<'a> { } } debug!("exports: {:#?}", exports); - if let Some(&import_table) = optional_header.data_directories.get_import_table() { + if let Some(import_table) = *optional_header.data_directories.get_import_table() { let id = if is_64 { import::ImportData::parse_with_opts::( bytes, @@ -204,7 +196,7 @@ impl<'a> PE<'a> { import_data = Some(id); } debug!("imports: {:#?}", imports); - if let Some(&debug_table) = optional_header.data_directories.get_debug_table() { + if let Some(debug_table) = *optional_header.data_directories.get_debug_table() { debug_data = Some(debug::DebugData::parse_with_opts( bytes, debug_table, @@ -217,8 +209,8 @@ impl<'a> PE<'a> { if header.coff_header.machine == header::COFF_MACHINE_X86_64 { // currently only x86_64 is supported debug!("exception data: {:#?}", exception_data); - if let Some(&exception_table) = - optional_header.data_directories.get_exception_table() + if let Some(exception_table) = + *optional_header.data_directories.get_exception_table() { exception_data = Some(exception::ExceptionData::parse_with_opts( bytes, @@ -230,30 +222,26 @@ impl<'a> PE<'a> { } } - // Parse attribute certificates unless opted out of - let certificate_table_size = if opts.parse_attribute_certificates { - if let Some(&certificate_table) = - optional_header.data_directories.get_certificate_table() - { - certificates = certificate_table::enumerate_certificates( - bytes, - certificate_table.virtual_address, - certificate_table.size, - )?; + let certtable = if let Some(certificate_table) = + *optional_header.data_directories.get_certificate_table() + { + certificates = certificate_table::enumerate_certificates( + bytes, + certificate_table.virtual_address, + certificate_table.size, + )?; - certificate_table.size as usize - } else { - 0 - } + let start = certificate_table.virtual_address as usize; + let end = start + certificate_table.size as usize; + Some(start..end) } else { - 0 + None }; authenticode_excluded_sections = Some(authenticode::ExcludedSections::new( checksum, datadir_entry_certtable, - certificate_table_size, - optional_header.windows_fields.size_of_headers as usize, + certtable, )); } Ok(PE { @@ -277,192 +265,6 @@ impl<'a> PE<'a> { certificates, }) } - - pub fn write_sections( - &self, - bytes: &mut [u8], - offset: &mut usize, - file_alignment: Option, - ctx: scroll::Endian, - ) -> Result { - // sections table and data - debug_assert!( - self.sections - .iter() - .flat_map(|section_a| { - self.sections - .iter() - .map(move |section_b| (section_a, section_b)) - }) - // given sections = (s_1, …, s_n) - // for all (s_i, s_j), i != j, verify that s_i does not overlap with s_j and vice versa. - .all(|(section_i, section_j)| section_i == section_j - || !section_i.overlaps_with(section_j)), - "Overlapping sections were found, this is not supported." - ); - - for section in &self.sections { - let section_data = section.data(&self.bytes)?.ok_or_else(|| { - error::Error::Malformed(format!( - "Section data `{}` is malformed", - section.name().unwrap_or("unknown name") - )) - })?; - let file_section_offset = - usize::try_from(section.pointer_to_raw_data).map_err(|_| { - error::Error::Malformed(format!( - "Section `{}`'s pointer to raw data does not fit in platform `usize`", - section.name().unwrap_or("unknown name") - )) - })?; - let vsize: usize = section.virtual_size.try_into()?; - let ondisk_size: usize = section.size_of_raw_data.try_into()?; - let section_name = String::from(section.name().unwrap_or("unknown name")); - - let mut file_offset = file_section_offset; - // `file_section_offset` is a on-disk offset which can be anywhere in the file. - // Write section data first to avoid the final consumption. - match section_data { - Cow::Borrowed(borrowed) => bytes.gwrite(borrowed, &mut file_offset)?, - Cow::Owned(owned) => bytes.gwrite(owned.as_slice(), &mut file_offset)?, - }; - - // Section tables follows the header. - bytes.gwrite_with(section, offset, ctx)?; - - // for size size_of_raw_data - // if < virtual_size, pad with 0 - // Pad with zeros if necessary - if file_offset < vsize { - bytes.gwrite(vec![0u8; vsize - file_offset].as_slice(), &mut file_offset)?; - } - - // Align on a boundary as per file alignement field. - if let Some(pad) = pad(file_offset - file_section_offset, file_alignment) { - debug!( - "aligning `{}` {:#x} -> {:#x} bytes'", - section_name, - file_offset - file_section_offset, - file_offset - file_section_offset + pad.len() - ); - bytes.gwrite(pad.as_slice(), &mut file_offset)?; - } - - let written_data_size = file_offset - file_section_offset; - if ondisk_size != written_data_size { - warn!("Original PE is inefficient or bug (on-disk data size in PE: {:#x}), we wrote {:#x} bytes", - ondisk_size, - written_data_size); - } - } - - Ok(*offset) - } - - pub fn write_certificates( - &self, - bytes: &mut [u8], - ctx: scroll::Endian, - ) -> Result { - let opt_header = self - .header - .optional_header - .ok_or(error::Error::Malformed(format!( - "This PE binary has no optional header; it is required to write certificates" - )))?; - let mut max_offset = 0; - - if let Some(certificate_directory) = opt_header.data_directories.get_certificate_table() { - let mut certificate_start = certificate_directory.virtual_address.try_into()?; - for certificate in &self.certificates { - bytes.gwrite_with(certificate, &mut certificate_start, ctx)?; - max_offset = max(certificate_start, max_offset); - } - } - - Ok(max_offset) - } -} - -impl<'a> ctx::TryIntoCtx for PE<'a> { - type Error = error::Error; - - fn try_into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) -> Result { - let mut offset = 0; - // We need to maintain a `max_offset` because - // we could be writing sections in the wrong order (i.e. not an increasing order for the - // pointer on raw disk) - // and there could be holes between sections. - // If we don't re-layout sections, we cannot fix that ourselves. - // Same can be said about the certificate table, there could be a hole between sections - // and the certificate data. - // To avoid those troubles, we maintain the max over all offsets we see so far. - let mut max_offset = 0; - let file_alignment: Option = match self.header.optional_header { - Some(opt_header) => { - debug_assert!( - opt_header.windows_fields.file_alignment.count_ones() == 1, - "file alignment should be a power of 2" - ); - Some(opt_header.windows_fields.file_alignment.try_into()?) - } - _ => None, - }; - bytes.gwrite_with(self.header, &mut offset, ctx)?; - max_offset = max(offset, max_offset); - self.write_sections(bytes, &mut offset, file_alignment, ctx)?; - // We want the section offset for which we have the highest pointer on disk. - // The next offset is reserved for debug tables (outside of sections) and/or certificate - // tables. - max_offset = max( - self.sections - .iter() - .max_by_key(|section| section.pointer_to_raw_data as usize) - .map(|section| (section.pointer_to_raw_data + section.size_of_raw_data) as usize) - .unwrap_or(offset), - max_offset, - ); - - // COFF Symbol Table - // Auxiliary Symbol Records - // COFF String Table - assert!( - self.header.coff_header.pointer_to_symbol_table == 0, - "Symbol tables in PE are deprecated and not supported to write" - ); - - // The following data directories are - // taken care inside a section: - // - export table (.edata) - // - import table (.idata) - // - bound import table - // - import address table - // - delay import tables - // - resource table (.rsrc) - // - exception table (.pdata) - // - base relocation table (.reloc) - // - debug table (.debug) <- this one is special, it can be outside of a - // section. - // - load config table - // - tls table (.tls) - // - architecture (reserved, 0 for now) - // - global ptr is a "empty" data directory (header-only) - // - clr runtime header (.cormeta is object-only) - // - // Nonetheless, we need to write the attribute certificate table one. - max_offset = max(max_offset, self.write_certificates(bytes, ctx)?); - - // TODO: we would like to support debug table outside of a section. - // i.e. debug tables that are never mapped in memory - // See https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#debug-directory-image-only - // > The debug directory can be in a discardable .debug section (if one exists), or it can be included in any other section in the image file, or not be in a section at all. - // In case it's not in a section at all, we need to find a way - // to rewrite it again. - // and we need to respect the ordering between attribute certificates - // and debug table. - - Ok(max_offset) - } } /// An analyzed COFF object @@ -472,12 +274,10 @@ pub struct Coff<'a> { pub header: header::CoffHeader, /// A list of the sections in this COFF binary pub sections: Vec, - /// The COFF symbol table, they are not guaranteed to exist. - /// For an image, this is expected to be None as COFF debugging information - /// has been deprecated. - pub symbols: Option>, - /// The string table, they don't exist if COFF symbol table does not exist. - pub strings: Option>, + /// The COFF symbol table. + pub symbols: symbol::SymbolTable<'a>, + /// The string table. + pub strings: strtab::Strtab<'a>, } impl<'a> Coff<'a> { @@ -614,7 +414,7 @@ mod tests { #[test] fn string_table_excludes_length() { let coff = Coff::parse(&&COFF_FILE_SINGLE_STRING_IN_STRING_TABLE[..]).unwrap(); - let string_table = coff.strings.unwrap().to_vec().unwrap(); + let string_table = coff.strings.to_vec().unwrap(); assert!(string_table == vec!["ExitProcess"]); } @@ -622,10 +422,9 @@ mod tests { #[test] fn symbol_name_excludes_length() { let coff = Coff::parse(&COFF_FILE_SINGLE_STRING_IN_STRING_TABLE).unwrap(); - let strings = coff.strings.unwrap(); + let strings = coff.strings; let symbols = coff .symbols - .unwrap() .iter() .filter(|(_, name, _)| name.is_none()) .map(|(_, _, sym)| sym.name(&strings).unwrap().to_owned()) diff --git a/third_party/rust/goblin/src/pe/optional_header.rs b/third_party/rust/goblin/src/pe/optional_header.rs index 852f4dced0f5..b1d3192764ea 100644 --- a/third_party/rust/goblin/src/pe/optional_header.rs +++ b/third_party/rust/goblin/src/pe/optional_header.rs @@ -71,22 +71,6 @@ impl From for StandardFields { } } -impl From for StandardFields32 { - fn from(fields: StandardFields) -> Self { - StandardFields32 { - magic: fields.magic, - major_linker_version: fields.major_linker_version, - minor_linker_version: fields.minor_linker_version, - size_of_code: fields.size_of_code as u32, - size_of_initialized_data: fields.size_of_initialized_data as u32, - size_of_uninitialized_data: fields.size_of_uninitialized_data as u32, - address_of_entry_point: fields.address_of_entry_point as u32, - base_of_code: fields.base_of_code as u32, - base_of_data: fields.base_of_data, - } - } -} - impl From for StandardFields { fn from(fields: StandardFields64) -> Self { StandardFields { @@ -103,21 +87,6 @@ impl From for StandardFields { } } -impl From for StandardFields64 { - fn from(fields: StandardFields) -> Self { - StandardFields64 { - magic: fields.magic, - major_linker_version: fields.major_linker_version, - minor_linker_version: fields.minor_linker_version, - size_of_code: fields.size_of_code as u32, - size_of_initialized_data: fields.size_of_initialized_data as u32, - size_of_uninitialized_data: fields.size_of_uninitialized_data as u32, - address_of_entry_point: fields.address_of_entry_point as u32, - base_of_code: fields.base_of_code as u32, - } - } -} - /// Standard fields magic number for 32-bit binary pub const MAGIC_32: u16 = 0x10b; /// Standard fields magic number for 64-bit binary @@ -239,36 +208,6 @@ impl From for WindowsFields { } } -impl TryFrom for WindowsFields32 { - type Error = crate::error::Error; - - fn try_from(value: WindowsFields64) -> Result { - Ok(WindowsFields32 { - image_base: value.image_base.try_into()?, - section_alignment: value.section_alignment, - file_alignment: value.file_alignment, - major_operating_system_version: value.major_operating_system_version, - minor_operating_system_version: value.minor_operating_system_version, - major_image_version: value.major_image_version, - minor_image_version: value.minor_image_version, - major_subsystem_version: value.major_subsystem_version, - minor_subsystem_version: value.minor_subsystem_version, - win32_version_value: value.win32_version_value, - size_of_image: value.size_of_image, - size_of_headers: value.size_of_headers, - check_sum: value.check_sum, - subsystem: value.subsystem, - dll_characteristics: value.dll_characteristics, - size_of_stack_reserve: value.size_of_stack_reserve.try_into()?, - size_of_stack_commit: value.size_of_stack_commit.try_into()?, - size_of_heap_reserve: value.size_of_heap_reserve.try_into()?, - size_of_heap_commit: value.size_of_heap_commit.try_into()?, - loader_flags: value.loader_flags, - number_of_rva_and_sizes: value.number_of_rva_and_sizes, - }) - } -} - // impl From for WindowsFields { // fn from(windows: WindowsFields32) -> Self { // WindowsFields { @@ -350,28 +289,6 @@ impl<'a> ctx::TryFromCtx<'a, Endian> for OptionalHeader { } } -impl ctx::TryIntoCtx for OptionalHeader { - type Error = error::Error; - - fn try_into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) -> Result { - let offset = &mut 0; - match self.standard_fields.magic { - MAGIC_32 => { - bytes.gwrite_with::(self.standard_fields.into(), offset, ctx)?; - bytes.gwrite_with(WindowsFields32::try_from(self.windows_fields)?, offset, ctx)?; - bytes.gwrite_with(self.data_directories, offset, ctx)?; - } - MAGIC_64 => { - bytes.gwrite_with::(self.standard_fields.into(), offset, ctx)?; - bytes.gwrite_with(self.windows_fields, offset, ctx)?; - bytes.gwrite_with(self.data_directories, offset, ctx)?; - } - _ => panic!(), - } - Ok(*offset) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/third_party/rust/goblin/src/pe/options.rs b/third_party/rust/goblin/src/pe/options.rs index 4461a4c7bd1f..5fea632f759f 100644 --- a/third_party/rust/goblin/src/pe/options.rs +++ b/third_party/rust/goblin/src/pe/options.rs @@ -3,19 +3,11 @@ pub struct ParseOptions { /// Wether the parser should resolve rvas or not. Default: true pub resolve_rva: bool, - /// Whether or not to parse attribute certificates. - /// Set to false for in-memory representation, as the [loader does not map this info into - /// memory](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#other-contents-of-the-file). - /// For on-disk representations, leave as true. Default: true - pub parse_attribute_certificates: bool, } impl ParseOptions { /// Returns a parse options structure with default values pub fn default() -> Self { - ParseOptions { - resolve_rva: true, - parse_attribute_certificates: true, - } + ParseOptions { resolve_rva: true } } } diff --git a/third_party/rust/goblin/src/pe/section_table.rs b/third_party/rust/goblin/src/pe/section_table.rs index f49c2b689ccc..4491827f166c 100644 --- a/third_party/rust/goblin/src/pe/section_table.rs +++ b/third_party/rust/goblin/src/pe/section_table.rs @@ -1,8 +1,6 @@ use crate::error::{self, Error}; use crate::pe::relocation; -use alloc::borrow::Cow; use alloc::string::{String, ToString}; -use alloc::vec::Vec; use scroll::{ctx, Pread, Pwrite}; #[repr(C)] @@ -81,32 +79,6 @@ impl SectionTable { Ok(table) } - pub fn data<'a, 'b: 'a>(&'a self, pe_bytes: &'b [u8]) -> error::Result>> { - let section_start: usize = self.pointer_to_raw_data.try_into().map_err(|_| { - Error::Malformed(format!("Virtual address cannot fit in platform `usize`")) - })?; - - // assert!(self.virtual_size <= self.size_of_raw_data); - // if vsize > size_of_raw_data, the section is zero padded. - let section_end: usize = section_start - + usize::try_from(self.size_of_raw_data).map_err(|_| { - Error::Malformed(format!("Virtual size cannot fit in platform `usize`")) - })?; - - let original_bytes = pe_bytes.get(section_start..section_end).map(Cow::Borrowed); - - if original_bytes.is_some() && self.virtual_size > self.size_of_raw_data { - let mut bytes: Vec = Vec::new(); - bytes.resize(self.size_of_raw_data.try_into()?, 0); - bytes.copy_from_slice(&original_bytes.unwrap()); - bytes.resize(self.virtual_size.try_into()?, 0); - - Ok(Some(Cow::Owned(bytes))) - } else { - Ok(original_bytes) - } - } - pub fn name_offset(&self) -> error::Result> { // Based on https://github.com/llvm-mirror/llvm/blob/af7b1832a03ab6486c42a40d21695b2c03b2d8a3/lib/Object/COFFObjectFile.cpp#L1054 if self.name[0] == b'/' { @@ -191,15 +163,6 @@ impl SectionTable { let number = self.number_of_relocations as usize; relocation::Relocations::parse(bytes, offset, number) } - - /// Tests if `another_section` on-disk ranges will collide. - pub fn overlaps_with(&self, another_section: &SectionTable) -> bool { - let self_end = self.pointer_to_raw_data + self.size_of_raw_data; - let another_end = another_section.pointer_to_raw_data + another_section.size_of_raw_data; - - !((self_end <= another_section.pointer_to_raw_data) - || (another_end <= self.pointer_to_raw_data)) - } } impl ctx::SizeWith for SectionTable { @@ -208,7 +171,7 @@ impl ctx::SizeWith for SectionTable { } } -impl ctx::TryIntoCtx for &SectionTable { +impl ctx::TryIntoCtx for SectionTable { type Error = error::Error; fn try_into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) -> Result { let offset = &mut 0; @@ -226,7 +189,7 @@ impl ctx::TryIntoCtx for &SectionTable { } } -impl ctx::IntoCtx for &SectionTable { +impl ctx::IntoCtx for SectionTable { fn into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) { bytes.pwrite_with(self, 0, ctx).unwrap(); } diff --git a/third_party/rust/goblin/src/pe/symbol.rs b/third_party/rust/goblin/src/pe/symbol.rs index e5aba25beca7..b2ced808a122 100644 --- a/third_party/rust/goblin/src/pe/symbol.rs +++ b/third_party/rust/goblin/src/pe/symbol.rs @@ -412,7 +412,6 @@ pub struct AuxSectionDefinition { } /// A COFF symbol table. -// TODO: #[derive(Pwrite)] produce unparseable tokens pub struct SymbolTable<'a> { symbols: &'a [u8], } @@ -484,14 +483,6 @@ impl<'a> SymbolTable<'a> { } } -impl<'a> ctx::TryIntoCtx for SymbolTable<'a> { - type Error = error::Error; - - fn try_into_ctx(self, bytes: &mut [u8], _ctx: scroll::Endian) -> Result { - bytes.pwrite(self.symbols, 0).map_err(|err| err.into()) - } -} - impl<'a> Debug for SymbolTable<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("SymbolTable") diff --git a/third_party/rust/goblin/src/pe/utils.rs b/third_party/rust/goblin/src/pe/utils.rs index 289ccc529b85..07a320d57b24 100644 --- a/third_party/rust/goblin/src/pe/utils.rs +++ b/third_party/rust/goblin/src/pe/utils.rs @@ -1,6 +1,5 @@ use crate::error; use alloc::string::ToString; -use alloc::vec::Vec; use scroll::Pread; use super::options; @@ -179,18 +178,3 @@ where let result: T = bytes.pread_with(offset, scroll::LE)?; Ok(result) } - -pub(crate) fn pad(length: usize, alignment: Option) -> Option> { - match alignment { - Some(alignment) => { - let overhang = length % alignment; - if overhang != 0 { - let repeat = alignment - overhang; - Some(vec![0u8; repeat]) - } else { - None - } - } - None => None, - } -} diff --git a/third_party/rust/goblin/src/strtab.rs b/third_party/rust/goblin/src/strtab.rs index 487d8d427914..dc7b8080f038 100644 --- a/third_party/rust/goblin/src/strtab.rs +++ b/third_party/rust/goblin/src/strtab.rs @@ -34,11 +34,6 @@ impl<'a> Strtab<'a> { Self::from_slice_unparsed(bytes, 0, bytes.len(), delim) } - /// Returns the length of this `Strtab` in bytes - pub fn len(&self) -> usize { - self.bytes.len() - } - /// Creates a `Strtab` directly without bounds check and without parsing it. /// /// This is potentially unsafe and should only be used if `feature = "alloc"` is disabled. diff --git a/third_party/rust/oneshot-uniffi/.cargo-checksum.json b/third_party/rust/oneshot-uniffi/.cargo-checksum.json index 985beded51fa..6b252c67732c 100644 --- a/third_party/rust/oneshot-uniffi/.cargo-checksum.json +++ b/third_party/rust/oneshot-uniffi/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"4ad03d95d5532e8f2551e3e53877e6347c04c32f479c4edf517244ecd5921ac7","Cargo.lock":"5d85bcfda2ee559d243099fb26f3724ae239777d891e780a924804e30f6733ad","Cargo.toml":"07a73ff74274df3a7439fccc8acfe306fae0f51ad79a80edbc54b51a730314c0","README.md":"811ea1c958d5a65583d0223b7ab09bb282e7a51ed60f9a2cb90ef6d555325a68","benches/benches.rs":"67dcc916d0b7e28e396c28dac0499726366e1cb10e9991948d1c881a5abf5faa","check_mem_leaks.sh":"c1ab6ef27997c7f971352ab1c86a184004843c499bc24925da953aefcf1c624c","examples/recv_before_send.rs":"9a3cabcc2878990b61787d0048061b382555a8cd1a08b1ddec63a6e8a4a31e56","examples/recv_before_send_then_drop_sender.rs":"14706c6b4308a690662ceaa47f1699588bd833b3ec020eb9f42f220f3ffc7ae7","examples/recv_ref_before_send.rs":"43699f4720c46b5f138c260b866eb708ddf616e2b442ffa74a97373f4f48d4d0","examples/recv_ref_before_send_then_drop_sender.rs":"a190ed220cb4288d4965485365c9afaed30535cbfad5f8cb7389071b82d67cac","examples/recv_timeout_before_send.rs":"2262aa6531afce7816d43182ad9cbec2c04f3dc129064e11e89452278ce8b163","examples/recv_timeout_before_send_then_drop_sender.rs":"4cc8eade4c211f52f5b9be0f72a5906689b894490f4cb5255525e44106e7a4a8","examples/recv_with_dropped_sender.rs":"7906685053ce1c53ff6c26ce11d3221d4bf5ca3429d1d4d2c28de9237cb151c6","examples/send_before_recv.rs":"5555bd61ad52273b663007794128d8f012fc54272bd3225259b5546221bcd591","examples/send_then_drop_receiver.rs":"c3612de207309098404b057468687a2d2311d07f354b7e046398e35e93c4cdcf","examples/send_with_dropped_receiver.rs":"f5a7762b231a24a0db4397c5139437cba155d09b9dbb59872d662c7923080706","src/errors.rs":"a5aa56bc497dccdbdbe15b9070360f50835c762f11be4ee96e0d25b150168ac9","src/lib.rs":"4bef3602ff4f5d2b42ce963d722a48c9ff07275e75ef6bed7b523e8f45e459fe","src/loombox.rs":"fc85d1c2d3fda432be60f0c4d1d528e5998ec2b738a5b395a242285051b94d65","tests/assert_mem.rs":"b1e5190af01af22e55c7c1cd1ff2711807591f788e4eb8b6c6d89123e146105e","tests/async.rs":"6fd2826e589b94677d4eeed1080deda8bcc429aa05a20d843d1442a3a48ea757","tests/future.rs":"0e71f0293cd5a8c44210e8882aca20cfbf1e3771ecd4e4f6b59b924c0d01dd97","tests/helpers/mod.rs":"19161ed33e0ba8862746f04678d0606dee90205896083f85d8c1dcd4d211ccb0","tests/helpers/waker.rs":"77494d49f62d0d320df3830643c306e06e6e20751d210cf6fa58b238bd96c3f9","tests/loom.rs":"ea350fa424a95581e1871bc0037badecc5a090f28fd10532917abbaf561218ab","tests/raw.rs":"5564615fea811b0061d8ad801356e60e0018ec4e3fb99cc739287ed5b96cb7cf","tests/sync.rs":"1186fa6cdb5a180944fa7d793ccb8be412c4a4e88bb504daa70bc097ee081b06"},"package":"6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c"} \ No newline at end of file +{"files":{"CHANGELOG.md":"e1165d97c283b915d87e22f209494be39933723a0b544e725f69cfa5cef3876c","Cargo.lock":"7625529900ca1e3626b90e74ef268b31e06da85e8334a885711fdfd80821ddda","Cargo.toml":"81dde8ad3180c7b97325a6a67bfbefb145590606de9008d881c4e04808865f0a","README.md":"811ea1c958d5a65583d0223b7ab09bb282e7a51ed60f9a2cb90ef6d555325a68","benches/benches.rs":"67dcc916d0b7e28e396c28dac0499726366e1cb10e9991948d1c881a5abf5faa","check_mem_leaks.sh":"c1ab6ef27997c7f971352ab1c86a184004843c499bc24925da953aefcf1c624c","examples/recv_before_send.rs":"9a3cabcc2878990b61787d0048061b382555a8cd1a08b1ddec63a6e8a4a31e56","examples/recv_before_send_then_drop_sender.rs":"14706c6b4308a690662ceaa47f1699588bd833b3ec020eb9f42f220f3ffc7ae7","examples/recv_ref_before_send.rs":"43699f4720c46b5f138c260b866eb708ddf616e2b442ffa74a97373f4f48d4d0","examples/recv_ref_before_send_then_drop_sender.rs":"a190ed220cb4288d4965485365c9afaed30535cbfad5f8cb7389071b82d67cac","examples/recv_timeout_before_send.rs":"2262aa6531afce7816d43182ad9cbec2c04f3dc129064e11e89452278ce8b163","examples/recv_timeout_before_send_then_drop_sender.rs":"4cc8eade4c211f52f5b9be0f72a5906689b894490f4cb5255525e44106e7a4a8","examples/recv_with_dropped_sender.rs":"7906685053ce1c53ff6c26ce11d3221d4bf5ca3429d1d4d2c28de9237cb151c6","examples/send_before_recv.rs":"5555bd61ad52273b663007794128d8f012fc54272bd3225259b5546221bcd591","examples/send_then_drop_receiver.rs":"c3612de207309098404b057468687a2d2311d07f354b7e046398e35e93c4cdcf","examples/send_with_dropped_receiver.rs":"f5a7762b231a24a0db4397c5139437cba155d09b9dbb59872d662c7923080706","src/errors.rs":"df6a1db663fdb1c54d6941d737f6591bfe0dc6f01bd627ba0a94d67ed50b27a9","src/lib.rs":"86893f56e8e762b41ee079b42f4248608e9efb68bd76aa9550fce61e7466bbb0","src/loombox.rs":"fc85d1c2d3fda432be60f0c4d1d528e5998ec2b738a5b395a242285051b94d65","tests/assert_mem.rs":"b1e5190af01af22e55c7c1cd1ff2711807591f788e4eb8b6c6d89123e146105e","tests/async.rs":"6fd2826e589b94677d4eeed1080deda8bcc429aa05a20d843d1442a3a48ea757","tests/future.rs":"0e71f0293cd5a8c44210e8882aca20cfbf1e3771ecd4e4f6b59b924c0d01dd97","tests/helpers/mod.rs":"19161ed33e0ba8862746f04678d0606dee90205896083f85d8c1dcd4d211ccb0","tests/helpers/waker.rs":"77494d49f62d0d320df3830643c306e06e6e20751d210cf6fa58b238bd96c3f9","tests/loom.rs":"ea350fa424a95581e1871bc0037badecc5a090f28fd10532917abbaf561218ab","tests/sync.rs":"1186fa6cdb5a180944fa7d793ccb8be412c4a4e88bb504daa70bc097ee081b06"},"package":"9ae4988774e7a7e6a0783d119bdc683ea8c1d01a24d4fff9b4bdc280e07bd99e"} \ No newline at end of file diff --git a/third_party/rust/oneshot-uniffi/CHANGELOG.md b/third_party/rust/oneshot-uniffi/CHANGELOG.md index c4c928386b1b..e12f6cc979d8 100644 --- a/third_party/rust/oneshot-uniffi/CHANGELOG.md +++ b/third_party/rust/oneshot-uniffi/CHANGELOG.md @@ -16,13 +16,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] - -## [0.1.6] - 2023-09-14 -### Added -* Add `into_raw` and `from_raw` methods on both `Sender` and `Receiver`. Allows passing `oneshot` - channels over FFI without an extra layer of heap allocation. - - ## [0.1.5] - 2022-09-01 ### Fixed - Handle the UNPARKING state correctly in all recv methods. `try_recv` will now not panic diff --git a/third_party/rust/oneshot-uniffi/Cargo.lock b/third_party/rust/oneshot-uniffi/Cargo.lock index b71644917fd4..1b75d4367504 100644 --- a/third_party/rust/oneshot-uniffi/Cargo.lock +++ b/third_party/rust/oneshot-uniffi/Cargo.lock @@ -601,7 +601,7 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "oneshot-uniffi" -version = "0.1.6" +version = "0.1.5" dependencies = [ "async-std", "criterion", diff --git a/third_party/rust/oneshot-uniffi/Cargo.toml b/third_party/rust/oneshot-uniffi/Cargo.toml index cba72669159b..078a477fb23d 100644 --- a/third_party/rust/oneshot-uniffi/Cargo.toml +++ b/third_party/rust/oneshot-uniffi/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.60.0" name = "oneshot-uniffi" -version = "0.1.6" +version = "0.1.5" authors = ["Linus Färnstrand "] description = """ Patched version of oneshot specifically for the UniFFI project. diff --git a/third_party/rust/oneshot-uniffi/src/errors.rs b/third_party/rust/oneshot-uniffi/src/errors.rs index 1fd0de1eed8b..afc48acd03ce 100644 --- a/third_party/rust/oneshot-uniffi/src/errors.rs +++ b/third_party/rust/oneshot-uniffi/src/errors.rs @@ -4,8 +4,7 @@ use core::mem; use core::ptr::NonNull; /// An error returned when trying to send on a closed channel. Returned from -/// [`Sender::send`](crate::Sender::send) if the corresponding [`Receiver`](crate::Receiver) -/// has already been dropped. +/// [`Sender::send`] if the corresponding [`Receiver`] has already been dropped. /// /// The message that could not be sent can be retreived again with [`SendError::into_inner`]. pub struct SendError { @@ -80,10 +79,10 @@ impl fmt::Debug for SendError { #[cfg(feature = "std")] impl std::error::Error for SendError {} -/// An error returned from the blocking [`Receiver::recv`](crate::Receiver::recv) method. +/// An error returned from the indefinitely blocking recv functions on a [`Receiver`]. /// -/// The receive operation can only fail if the corresponding [`Sender`](crate::Sender) was dropped -/// before sending any message, or if a message has already been sent and received on the channel. +/// The recv operation can only fail if the corresponding [`Sender`] was dropped before sending +/// any message. Or if a message has already been sent and received on the channel. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct RecvError; @@ -96,8 +95,7 @@ impl fmt::Display for RecvError { #[cfg(feature = "std")] impl std::error::Error for RecvError {} -/// An error returned when failing to receive a message in the non-blocking -/// [`Receiver::try_recv`](crate::Receiver::try_recv). +/// An error returned when trying a non blocking receive on a [`Receiver`]. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum TryRecvError { /// The channel is still open, but there was no message present in it. @@ -121,8 +119,7 @@ impl fmt::Display for TryRecvError { #[cfg(feature = "std")] impl std::error::Error for TryRecvError {} -/// An error returned when failing to receive a message in -/// [`Receiver::recv_timeout`](crate::Receiver::recv_timeout). +/// An error returned when trying a time limited blocking receive on a [`Receiver`]. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum RecvTimeoutError { /// No message arrived on the channel before the timeout was reached. The channel is still open. diff --git a/third_party/rust/oneshot-uniffi/src/lib.rs b/third_party/rust/oneshot-uniffi/src/lib.rs index 8da012b8c04a..94bb35d12ac0 100644 --- a/third_party/rust/oneshot-uniffi/src/lib.rs +++ b/third_party/rust/oneshot-uniffi/src/lib.rs @@ -314,31 +314,6 @@ impl Sender { _ => unreachable!(), } } - - /// Consumes the Sender, returning a raw pointer to the channel on the heap. - /// - /// This is intended to simplify using oneshot channels with some FFI code. The only safe thing - /// to do with the returned pointer is to later reconstruct the Sender with [Sender::from_raw]. - /// Memory will leak if the Sender is never reconstructed. - pub fn into_raw(self) -> *mut () { - let raw = self.channel_ptr.as_ptr() as *mut (); - mem::forget(self); - raw - } - - /// Consumes a raw pointer from [Sender::into_raw], recreating the Sender. - /// - /// # Safety - /// - /// This pointer must have come from [`Sender::into_raw`] with the same message type, `T`. - /// At most one Sender must exist for a channel at any point in time. - /// Constructing multiple Senders from the same raw pointer leads to undefined behavior. - pub unsafe fn from_raw(raw: *mut ()) -> Self { - Self { - channel_ptr: NonNull::new_unchecked(raw as *mut Channel), - _invariant: PhantomData, - } - } } impl Drop for Sender { @@ -841,30 +816,6 @@ impl Receiver { _ => unreachable!(), } } - - /// Consumes the Receiver, returning a raw pointer to the channel on the heap. - /// - /// This is intended to simplify using oneshot channels with some FFI code. The only safe thing - /// to do with the returned pointer is to later reconstruct the Receiver with - /// [Receiver::from_raw]. Memory will leak if the Receiver is never reconstructed. - pub fn into_raw(self) -> *mut () { - let raw = self.channel_ptr.as_ptr() as *mut (); - mem::forget(self); - raw - } - - /// Consumes a raw pointer from [Receiver::into_raw], recreating the Receiver. - /// - /// # Safety - /// - /// This pointer must have come from [`Receiver::into_raw`] with the same message type, `T`. - /// At most one Receiver must exist for a channel at any point in time. - /// Constructing multiple Receivers from the same raw pointer leads to undefined behavior. - pub unsafe fn from_raw(raw: *mut ()) -> Self { - Self { - channel_ptr: NonNull::new_unchecked(raw as *mut Channel), - } - } } #[cfg(feature = "async")] @@ -1227,7 +1178,7 @@ fn receiver_waker_size() { (false, false) => 0, (false, true) => 16, (true, false) => 8, - (true, true) => 16, + (true, true) => 24, }; assert_eq!(mem::size_of::(), expected); } diff --git a/third_party/rust/oneshot-uniffi/tests/raw.rs b/third_party/rust/oneshot-uniffi/tests/raw.rs deleted file mode 100644 index e38dc45c481c..000000000000 --- a/third_party/rust/oneshot-uniffi/tests/raw.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![cfg(not(loom))] - -use oneshot::{channel, Receiver, Sender}; - -#[test] -fn test_raw_sender() { - let (sender, receiver) = channel::(); - let raw = sender.into_raw(); - let recreated = unsafe { Sender::::from_raw(raw) }; - recreated - .send(100) - .unwrap_or_else(|e| panic!("error sending after into_raw/from_raw roundtrip: {e}")); - assert_eq!(receiver.try_recv(), Ok(100)) -} - -#[test] -fn test_raw_receiver() { - let (sender, receiver) = channel::(); - let raw = receiver.into_raw(); - sender.send(100).unwrap(); - let recreated = unsafe { Receiver::::from_raw(raw) }; - assert_eq!( - recreated - .try_recv() - .unwrap_or_else(|e| panic!("error receiving after into_raw/from_raw roundtrip: {e}")), - 100 - ) -} - -#[test] -fn test_raw_sender_and_receiver() { - let (sender, receiver) = channel::(); - let raw_receiver = receiver.into_raw(); - let raw_sender = sender.into_raw(); - - let recreated_sender = unsafe { Sender::::from_raw(raw_sender) }; - recreated_sender.send(100).unwrap(); - - let recreated_receiver = unsafe { Receiver::::from_raw(raw_receiver) }; - assert_eq!( - recreated_receiver - .try_recv() - .unwrap_or_else(|e| panic!("error receiving after into_raw/from_raw roundtrip: {e}")), - 100 - ) -} diff --git a/third_party/rust/relevancy/.cargo-checksum.json b/third_party/rust/relevancy/.cargo-checksum.json index c8d8187c8d2e..4f128a62f9fd 100644 --- a/third_party/rust/relevancy/.cargo-checksum.json +++ b/third_party/rust/relevancy/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"76d64a839128f51662d1c10728ceddbb6a9ebdfce803915874cd654117d1b14e","build.rs":"a562bfe527d21c4e8a1a44b892defa83cdff141ec5dd51ed6f3862330e50ddd7","src/bin/generate-test-data.rs":"7f1c9dc445418c7627f89d1f2aa8e550d0f85b3d1f05edb7c378ab9441714f1f","src/db.rs":"0b45180f3031759213a0421231b6f109ed4f5c88aca556df159ce2717416cfec","src/error.rs":"6831fc329044174a8451b8b008c0b96c47404c591eb42e880562e65da0adfd0f","src/interest.rs":"ce6298ef8f69fcb57c8e5797467cbe1c0212a0d94daf828b12845740ac14a166","src/lib.rs":"7a0f0ad0a43f371035d9c0b73d143cf1b387d4b8cfad0d0db79314b5b91fd43c","src/populate_interests.rs":"b8905b52f9fc80719c175253b758413f606b27660e660635094421eec8b24c8f","src/relevancy.udl":"a3fae5097f9e8b39bb6c74ed6789906748c46f22d377e3dcb73b08731908f5bc","src/schema.rs":"f782c712f10c4f1af2f9e1424d6b52f59a2bacfcc452a8feb763f36478f5dd5d","src/url_hash.rs":"5619a249d471e7b642d889bad09e93212559c8b947010d49492c1423da2b310e","test-data":"392fc950363c9953ea6ab144b81d84021c4af1e1177cc0adac4eda5688c8bc33"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"9cd293889d14141968761c609b8e472c332fc1c0656fff58602fd2993a537f98","build.rs":"a562bfe527d21c4e8a1a44b892defa83cdff141ec5dd51ed6f3862330e50ddd7","src/bin/generate-test-data.rs":"7f1c9dc445418c7627f89d1f2aa8e550d0f85b3d1f05edb7c378ab9441714f1f","src/db.rs":"0b45180f3031759213a0421231b6f109ed4f5c88aca556df159ce2717416cfec","src/error.rs":"6831fc329044174a8451b8b008c0b96c47404c591eb42e880562e65da0adfd0f","src/interest.rs":"ce6298ef8f69fcb57c8e5797467cbe1c0212a0d94daf828b12845740ac14a166","src/lib.rs":"7a0f0ad0a43f371035d9c0b73d143cf1b387d4b8cfad0d0db79314b5b91fd43c","src/populate_interests.rs":"b8905b52f9fc80719c175253b758413f606b27660e660635094421eec8b24c8f","src/relevancy.udl":"a3fae5097f9e8b39bb6c74ed6789906748c46f22d377e3dcb73b08731908f5bc","src/schema.rs":"f782c712f10c4f1af2f9e1424d6b52f59a2bacfcc452a8feb763f36478f5dd5d","src/url_hash.rs":"5619a249d471e7b642d889bad09e93212559c8b947010d49492c1423da2b310e","test-data":"392fc950363c9953ea6ab144b81d84021c4af1e1177cc0adac4eda5688c8bc33"},"package":null} \ No newline at end of file diff --git a/third_party/rust/relevancy/Cargo.toml b/third_party/rust/relevancy/Cargo.toml index eddd8fd25c54..c03f520974fb 100644 --- a/third_party/rust/relevancy/Cargo.toml +++ b/third_party/rust/relevancy/Cargo.toml @@ -29,7 +29,7 @@ log = "0.4" md-5 = "0.10" parking_lot = ">=0.11,<=0.12" thiserror = "1.0" -uniffi = "0.27.1" +uniffi = "0.25.2" url = "2.5" [dependencies.error-support] @@ -43,5 +43,5 @@ features = ["bundled"] path = "../support/sql" [build-dependencies.uniffi] -version = "0.27.1" +version = "0.25.2" features = ["build"] diff --git a/third_party/rust/remote_settings/.cargo-checksum.json b/third_party/rust/remote_settings/.cargo-checksum.json index 619a9d13cafc..8a2b63f31470 100644 --- a/third_party/rust/remote_settings/.cargo-checksum.json +++ b/third_party/rust/remote_settings/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"1029f571c66d33c4dfc5e9fc55287a780329ce183f5d2b672de79737155c4227","build.rs":"4326f03729cf8f1673e4228e6dc111de1ea4d8bcc06351f7ae563efb2613f866","src/client.rs":"7510ae0d5bcb9fbaa2c43c4773aa0fd518edc78fe0f396c0e1d6dd442446f429","src/config.rs":"7bb678addfae3b4ed5f2892d32263e5b33cc05e5a12a250f664150e78211f94a","src/error.rs":"192ca42af7c6b882f3129378c23b45dab8a0d2b179e23a8813a335ffd56b21dc","src/lib.rs":"416e99894e152f6cea7418ad2fabfd94bc3d907efd9f33fbd2a83fb99452b2df","src/remote_settings.udl":"2e71491ad3894d17e5bde0663d9490bfea6294d99cdbe9d67a36137faeedc593","uniffi.toml":"f8ec8dc593e0d501c2e9e40368ec93ec33b1edd8608e29495e0a54b63144e880"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"4fa89b0606fe8ec8ac8c479b8b9adf33d0c936b09fa5af108ded74139ace37fb","build.rs":"4326f03729cf8f1673e4228e6dc111de1ea4d8bcc06351f7ae563efb2613f866","src/client.rs":"fb3f2cd47460e5ae07a5e8d61b358d588d14075bd9dd6b6e818e1af74abd5dba","src/config.rs":"7bb678addfae3b4ed5f2892d32263e5b33cc05e5a12a250f664150e78211f94a","src/error.rs":"192ca42af7c6b882f3129378c23b45dab8a0d2b179e23a8813a335ffd56b21dc","src/lib.rs":"416e99894e152f6cea7418ad2fabfd94bc3d907efd9f33fbd2a83fb99452b2df","src/remote_settings.udl":"2e71491ad3894d17e5bde0663d9490bfea6294d99cdbe9d67a36137faeedc593","uniffi.toml":"f8ec8dc593e0d501c2e9e40368ec93ec33b1edd8608e29495e0a54b63144e880"},"package":null} \ No newline at end of file diff --git a/third_party/rust/remote_settings/Cargo.toml b/third_party/rust/remote_settings/Cargo.toml index 71d72079b74c..b04e6ed6c60a 100644 --- a/third_party/rust/remote_settings/Cargo.toml +++ b/third_party/rust/remote_settings/Cargo.toml @@ -28,7 +28,7 @@ license = "MPL-2.0" parking_lot = "0.12" serde_json = "1" thiserror = "1.0" -uniffi = "0.27.1" +uniffi = "0.25.2" url = "2.1" [dependencies.serde] @@ -46,5 +46,5 @@ mockito = "0.31" path = "../support/viaduct-reqwest" [build-dependencies.uniffi] -version = "0.27.1" +version = "0.25.2" features = ["build"] diff --git a/third_party/rust/remote_settings/src/client.rs b/third_party/rust/remote_settings/src/client.rs index 2cf26b73195b..0d99de9cc149 100644 --- a/third_party/rust/remote_settings/src/client.rs +++ b/third_party/rust/remote_settings/src/client.rs @@ -64,7 +64,7 @@ impl Client { /// collection defined by the [ClientConfig] used to generate this [Client]. pub fn get_records_since(&self, timestamp: u64) -> Result { self.get_records_with_options( - GetItemsOptions::new().filter_gt("last_modified", timestamp.to_string()), + GetItemsOptions::new().gt("last_modified", timestamp.to_string()), ) } @@ -307,7 +307,7 @@ struct AttachmentsCapability { } /// Options for requests to endpoints that return multiple items. -#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Debug, Default)] pub struct GetItemsOptions { filters: Vec, sort: Vec, @@ -328,14 +328,14 @@ impl GetItemsOptions { /// `author.name`. `value` can be a bare number or string (like /// `2` or `Ben`), or a stringified JSON value (`"2.0"`, `[1, 2]`, /// `{"checked": true}`). - pub fn filter_eq(&mut self, field: impl Into, value: impl Into) -> &mut Self { + pub fn eq(&mut self, field: impl Into, value: impl Into) -> &mut Self { self.filters.push(Filter::Eq(field.into(), value.into())); self } /// Sets an option to only return items whose `field` is not equal to the /// given `value`. - pub fn filter_not(&mut self, field: impl Into, value: impl Into) -> &mut Self { + pub fn not(&mut self, field: impl Into, value: impl Into) -> &mut Self { self.filters.push(Filter::Not(field.into(), value.into())); self } @@ -343,11 +343,7 @@ impl GetItemsOptions { /// Sets an option to only return items whose `field` is an array that /// contains the given `value`. If `value` is a stringified JSON array, the /// field must contain all its elements. - pub fn filter_contains( - &mut self, - field: impl Into, - value: impl Into, - ) -> &mut Self { + pub fn contains(&mut self, field: impl Into, value: impl Into) -> &mut Self { self.filters .push(Filter::Contains(field.into(), value.into())); self @@ -355,47 +351,47 @@ impl GetItemsOptions { /// Sets an option to only return items whose `field` is strictly less /// than the given `value`. - pub fn filter_lt(&mut self, field: impl Into, value: impl Into) -> &mut Self { + pub fn lt(&mut self, field: impl Into, value: impl Into) -> &mut Self { self.filters.push(Filter::Lt(field.into(), value.into())); self } /// Sets an option to only return items whose `field` is strictly greater /// than the given `value`. - pub fn filter_gt(&mut self, field: impl Into, value: impl Into) -> &mut Self { + pub fn gt(&mut self, field: impl Into, value: impl Into) -> &mut Self { self.filters.push(Filter::Gt(field.into(), value.into())); self } /// Sets an option to only return items whose `field` is less than or equal /// to the given `value`. - pub fn filter_max(&mut self, field: impl Into, value: impl Into) -> &mut Self { + pub fn max(&mut self, field: impl Into, value: impl Into) -> &mut Self { self.filters.push(Filter::Max(field.into(), value.into())); self } /// Sets an option to only return items whose `field` is greater than or /// equal to the given `value`. - pub fn filter_min(&mut self, field: impl Into, value: impl Into) -> &mut Self { + pub fn min(&mut self, field: impl Into, value: impl Into) -> &mut Self { self.filters.push(Filter::Min(field.into(), value.into())); self } /// Sets an option to only return items whose `field` is a string that /// contains the substring `value`. `value` can contain `*` wildcards. - pub fn filter_like(&mut self, field: impl Into, value: impl Into) -> &mut Self { + pub fn like(&mut self, field: impl Into, value: impl Into) -> &mut Self { self.filters.push(Filter::Like(field.into(), value.into())); self } /// Sets an option to only return items that have the given `field`. - pub fn filter_has(&mut self, field: impl Into) -> &mut Self { + pub fn has(&mut self, field: impl Into) -> &mut Self { self.filters.push(Filter::Has(field.into())); self } /// Sets an option to only return items that do not have the given `field`. - pub fn filter_has_not(&mut self, field: impl Into) -> &mut Self { + pub fn has_not(&mut self, field: impl Into) -> &mut Self { self.filters.push(Filter::HasNot(field.into())); self } @@ -458,7 +454,7 @@ impl GetItemsOptions { } /// The order in which to return items. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum SortOrder { /// Smaller values first. Ascending, @@ -466,7 +462,7 @@ pub enum SortOrder { Descending, } -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Debug)] enum Filter { Eq(String, String), Not(String, String), @@ -499,7 +495,7 @@ impl Filter { } } -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Debug)] struct Sort(String, SortOrder); impl Sort { @@ -696,16 +692,16 @@ mod test { .field("a") .field("c") .field("b") - .filter_eq("a", "b") - .filter_lt("c.d", "5") - .filter_gt("e", "15") - .filter_max("f", "20") - .filter_min("g", "10") - .filter_not("h", "i") - .filter_like("j", "*k*") - .filter_has("l") - .filter_has_not("m") - .filter_contains("n", "o") + .eq("a", "b") + .lt("c.d", "5") + .gt("e", "15") + .max("f", "20") + .min("g", "10") + .not("h", "i") + .like("j", "*k*") + .has("l") + .has_not("m") + .contains("n", "o") .sort("b", SortOrder::Descending) .sort("a", SortOrder::Ascending) .limit(3); diff --git a/third_party/rust/scroll/.cargo-checksum.json b/third_party/rust/scroll/.cargo-checksum.json dissimilarity index 100% index 4cdf2841c787..406f97faa290 100644 --- a/third_party/rust/scroll/.cargo-checksum.json +++ b/third_party/rust/scroll/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c9242ab52e0b3ba02d9557c3ef2070bc173dfbef05870c3c4831937233de38c0","LICENSE":"6e24b7455f0b9afefdf4f3efd59a56ce76a3020c2dc4371937e281fc5e587fd7","README.md":"7a7f6695853fbc174e3b016d72a8ef0113e313c897269779c7c368f102ed0c23","src/ctx.rs":"9bd92f1038962a8034450b64818cc7b5eaebacde2a229eec5b9cda3ec99c5ae4","src/endian.rs":"e3e0fcb99d0f71f739b6f0ea466a5d3479ed9c90f29269adb1aa2d725ac12af4","src/error.rs":"d91d332a87bde35738cc5915279fc0fde65301fe86ef98ec36126e1de9fd0474","src/greater.rs":"29d9736f9d35a0f92ca054c7a36878ade0a77b4e8ee27441c34cd81c6bdb68e6","src/leb128.rs":"eb71761d708f78c785e6dbe8d385fd90317d08369d1c3ac57d142ca7c0e09e9e","src/lesser.rs":"16fa2c3a737c126b7ac40117c960bc025fb418abc99559c244e8a5ae4348c730","src/lib.rs":"e9a1b9b0ee06ba39de6925f4bc23cb847c8ec3831ca37280c3660dc6d1b28826","src/pread.rs":"80eb931ad7340bba7e1a03a7cbef62c93537bdf4703e467210957d07b82f6489","src/pwrite.rs":"5384d97a57a245e057bca70bd3a386c2942c89f6f7555bcad498b348ee555543"},"package":"6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6"} \ No newline at end of file +{"files":{"CHANGELOG.md":"de2bbf4669561405d402322f4cc2604218d4986b73b75b41708b9505aebcb02c","Cargo.lock":"d6a215b7466d37e08551c56949e77be4ee488f989bdef3e507713c729bbda0e6","Cargo.toml":"c240c5768d23ea9611ef57308f08b8ee4372ede6c04f0783dc9fd1710e664c19","LICENSE":"6e24b7455f0b9afefdf4f3efd59a56ce76a3020c2dc4371937e281fc5e587fd7","README.md":"e4fe9aabcd87d85a5ec93241eeefc0d69aa0d98fbd67da2fe1849e4cbddac3ce","benches/bench.rs":"12ae02c383c91f1b0e11e9201eb8a9d44dadfb2b5987e7e71b0ef7c6589af1ca","examples/data_ctx.rs":"79684fc44d499d0b13a173184793837fbaba70d2f74f075e796eb37a1803ce3d","src/ctx.rs":"8f58672c5f3bc09b8f09c76f1d423431cbff786af75f5b39a0cef23b820d48c6","src/endian.rs":"5b717eb5ed0dc2b536779316b020df4e6489c05b13b4fd9b5f5e683aca1b2c28","src/error.rs":"a6a0ec9a6237d23febd608637c0e3926d147511e7983195366bc5a11f12d9093","src/greater.rs":"29d9736f9d35a0f92ca054c7a36878ade0a77b4e8ee27441c34cd81c6bdb68e6","src/leb128.rs":"e343f4e104ca6d8660a3dded30934b83bad4c04d8888ce2cbebfa562f5ac115d","src/lesser.rs":"d3028781977e60d67003512e45666935deab9a03c76a3ba9316a5dbdddf432eb","src/lib.rs":"49d02fa761bb2a771d1857ffd150aa4b6f55b4f03aee1a7a23d8181c76a55fd6","src/pread.rs":"64afdcf2c2785f1f23d065ec5e565d78569086dfd9ece0a3d2553b05aee5df9b","src/pwrite.rs":"05e3129ec666790a61f5b5f894ad863103e213eb798243cfe5f2cbb54d042ba1","tests/api.rs":"1bef345e020a6a4e590350ea4f6069c5836941656379e252bfbdaee6edbbc0de"},"package":"04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"} \ No newline at end of file diff --git a/third_party/rust/scroll/CHANGELOG.md b/third_party/rust/scroll/CHANGELOG.md new file mode 100644 index 000000000000..bae87ee5909e --- /dev/null +++ b/third_party/rust/scroll/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog +All notable changes to this project will be documented in this file. + +Before 1.0, this project does not adhere to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [0.10.0] - unreleased +### Added + - scroll is now 2018 compliant, thanks @lzutao: https://github.com/m4b/scroll/pull/49 + - scroll_derive now lives in scroll repo itself +### Removed + - BREAKING: removed units/size generics in SizeWith, thanks @willglynn: https://github.com/m4b/scroll/pull/45 + +## [0.9.1] - 2018-9-22 +### Added + - pread primitive references: https://github.com/m4b/scroll/pull/35 + - u128/i128 support: https://github.com/m4b/scroll/pull/32 + - CStr support: https://github.com/m4b/scroll/pull/30 diff --git a/third_party/rust/scroll/Cargo.lock b/third_party/rust/scroll/Cargo.lock new file mode 100644 index 000000000000..baf29fe04966 --- /dev/null +++ b/third_party/rust/scroll/Cargo.lock @@ -0,0 +1,205 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "byteorder" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const_fn" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" + +[[package]] +name = "crossbeam-channel" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +dependencies = [ + "cfg-if", + "const_fn", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" + +[[package]] +name = "memoffset" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scroll" +version = "0.11.0" +dependencies = [ + "byteorder", + "rayon", + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/third_party/rust/scroll/Cargo.toml b/third_party/rust/scroll/Cargo.toml index 70e9e8d1c366..548be72db926 100644 --- a/third_party/rust/scroll/Cargo.toml +++ b/third_party/rust/scroll/Cargo.toml @@ -11,37 +11,26 @@ [package] edition = "2021" -rust-version = "1.63" name = "scroll" -version = "0.12.0" -authors = [ - "m4b ", - "Ted Mielczarek ", -] -include = [ - "src/**/*", - "Cargo.toml", - "LICENSE", - "README.md", -] +version = "0.11.0" +authors = ["m4b ", "Ted Mielczarek "] description = "A suite of powerful, extensible, generic, endian-aware Read/Write traits for byte buffers" documentation = "https://docs.rs/scroll" readme = "README.md" -keywords = [ - "bytes", - "endian", - "immutable", - "pread", - "pwrite", -] +keywords = ["bytes", "endian", "immutable", "pread", "pwrite"] license = "MIT" repository = "https://github.com/m4b/scroll" - +resolver = "2" [dependencies.scroll_derive] -version = "0.12" +version = "0.11" optional = true +[dev-dependencies.byteorder] +version = "1" + +[dev-dependencies.rayon] +version = "1" [features] default = ["std"] -derive = ["dep:scroll_derive"] +derive = ["scroll_derive"] std = [] diff --git a/third_party/rust/scroll/README.md b/third_party/rust/scroll/README.md index 50dde54d7eba..717fe6a23419 100644 --- a/third_party/rust/scroll/README.md +++ b/third_party/rust/scroll/README.md @@ -1,13 +1,4 @@ -[![Actions][actions-badge]][actions-url] -[![crates.io version][crates-scroll-badge]][crates-scroll] - - - -[actions-badge]: https://github.com/m4b/scroll/workflows/CI/badge.svg?branch=master -[actions-url]: https://github.com/m4b/scroll/actions -[crates-scroll-badge]: https://img.shields.io/crates/v/scroll.svg -[crates-scroll]: https://crates.io/crates/scroll - + [![Build Status](https://travis-ci.org/m4b/scroll.svg?branch=master)](https://travis-ci.org/m4b/scroll) ## Scroll - cast some magic ```text @@ -32,7 +23,7 @@ Add to your `Cargo.toml` ```toml, no_test [dependencies] -scroll = "0.11" +scroll = "0.10" ``` ### Overview diff --git a/third_party/rust/scroll/benches/bench.rs b/third_party/rust/scroll/benches/bench.rs new file mode 100644 index 000000000000..0787dbe14bf1 --- /dev/null +++ b/third_party/rust/scroll/benches/bench.rs @@ -0,0 +1,157 @@ +#![feature(test)] +extern crate test; + +use scroll::{Cread, Pread, LE}; +use test::black_box; + +#[bench] +fn bench_parallel_cread_with(b: &mut test::Bencher) { + use rayon::prelude::*; + let vec = vec![0u8; 1_000_000]; + let nums = vec![0usize; 500_000]; + b.iter(|| { + let data = black_box(&vec[..]); + nums.par_iter().for_each(|offset| { + let _: u16 = black_box(data.cread_with(*offset, LE)); + }); + }); + b.bytes = vec.len() as u64; +} + +#[bench] +fn bench_cread_vec(b: &mut test::Bencher) { + let vec = vec![0u8; 1_000_000]; + b.iter(|| { + let data = black_box(&vec[..]); + for val in data.chunks(2) { + let _: u16 = black_box(val.cread_with(0, LE)); + } + }); + b.bytes = vec.len() as u64; +} + +#[bench] +fn bench_cread(b: &mut test::Bencher) { + const NITER: i32 = 100_000; + b.iter(|| { + for _ in 1..NITER { + let data = black_box([1, 2]); + let _: u16 = black_box(data.cread(0)); + } + }); + b.bytes = 2 * NITER as u64; +} + +#[bench] +fn bench_pread_ctx_vec(b: &mut test::Bencher) { + let vec = vec![0u8; 1_000_000]; + b.iter(|| { + let data = black_box(&vec[..]); + for val in data.chunks(2) { + let _: Result = black_box(val.pread(0)); + } + }); + b.bytes = vec.len() as u64; +} + +#[bench] +fn bench_pread_with_unwrap(b: &mut test::Bencher) { + const NITER: i32 = 100_000; + b.iter(|| { + for _ in 1..NITER { + let data: &[u8] = &black_box([1, 2]); + let _: u16 = black_box(data.pread_with(0, LE).unwrap()); + } + }); + b.bytes = 2 * NITER as u64; +} + +#[bench] +fn bench_pread_vec(b: &mut test::Bencher) { + let vec = vec![0u8; 1_000_000]; + b.iter(|| { + let data = black_box(&vec[..]); + for val in data.chunks(2) { + let _: Result = black_box(val.pread_with(0, LE)); + } + }); + b.bytes = vec.len() as u64; +} + +#[bench] +fn bench_pread_unwrap(b: &mut test::Bencher) { + const NITER: i32 = 100_000; + b.iter(|| { + for _ in 1..NITER { + let data = black_box([1, 2]); + let _: u16 = black_box(data.pread(0)).unwrap(); + } + }); + b.bytes = 2 * NITER as u64; +} + +#[bench] +fn bench_gread_vec(b: &mut test::Bencher) { + let vec = vec![0u8; 1_000_000]; + b.iter(|| { + let data = black_box(&vec[..]); + for val in data.chunks(2) { + let mut offset = 0; + let _: Result = black_box(val.gread(&mut offset)); + } + }); + b.bytes = vec.len() as u64; +} + +#[bench] +fn bench_gread_unwrap(b: &mut test::Bencher) { + const NITER: i32 = 100_000; + b.iter(|| { + for _ in 1..NITER { + let data = black_box([1, 2]); + let mut offset = 0; + let _: u16 = black_box(data.gread_with(&mut offset, LE).unwrap()); + } + }); + b.bytes = 2 * NITER as u64; +} + +#[bench] +fn bench_parallel_pread_with(b: &mut test::Bencher) { + use rayon::prelude::*; + let vec = vec![0u8; 1_000_000]; + let nums = vec![0usize; 500_000]; + b.iter(|| { + let data = black_box(&vec[..]); + nums.par_iter().for_each(|offset| { + let _: Result = black_box(data.pread_with(*offset, LE)); + }); + }); + b.bytes = vec.len() as u64; +} + +#[bench] +fn bench_byteorder_vec(b: &mut test::Bencher) { + use byteorder::ReadBytesExt; + let vec = vec![0u8; 1_000_000]; + b.iter(|| { + let data = black_box(&vec[..]); + for mut val in data.chunks(2) { + let _: Result = black_box(val.read_u16::()); + } + }); + b.bytes = vec.len() as u64; +} + +#[bench] +fn bench_byteorder(b: &mut test::Bencher) { + use byteorder::ByteOrder; + const NITER: i32 = 100_000; + b.iter(|| { + for _ in 1..NITER { + let data = black_box([1, 2]); + let _: u16 = black_box(byteorder::LittleEndian::read_u16(&data)); + } + }); + b.bytes = 2 * NITER as u64; +} diff --git a/third_party/rust/scroll/examples/data_ctx.rs b/third_party/rust/scroll/examples/data_ctx.rs new file mode 100644 index 000000000000..667f4b18f0dc --- /dev/null +++ b/third_party/rust/scroll/examples/data_ctx.rs @@ -0,0 +1,24 @@ +use scroll::{ctx, Endian, Pread, BE}; + +#[derive(Debug)] +struct Data<'a> { + name: &'a str, + id: u32, +} + +impl<'a> ctx::TryFromCtx<'a, Endian> for Data<'a> { + type Error = scroll::Error; + fn try_from_ctx(src: &'a [u8], endian: Endian) -> Result<(Self, usize), Self::Error> { + let name = src.pread::<&'a str>(0)?; + let id = src.pread_with(name.len() + 1, endian)?; + Ok((Data { name: name, id: id }, name.len() + 4)) + } +} + +fn main() { + let bytes = b"UserName\x00\x01\x02\x03\x04"; + let data = bytes.pread_with::(0, BE).unwrap(); + assert_eq!(data.id, 0x01020304); + assert_eq!(data.name.to_string(), "UserName".to_string()); + println!("Data: {:?}", &data); +} diff --git a/third_party/rust/scroll/src/ctx.rs b/third_party/rust/scroll/src/ctx.rs index e24d2dc50675..1f982b82fa40 100644 --- a/third_party/rust/scroll/src/ctx.rs +++ b/third_party/rust/scroll/src/ctx.rs @@ -180,14 +180,17 @@ //! } //! ``` -use core::mem::{size_of, MaybeUninit}; +use core::mem::size_of; +use core::mem::transmute; use core::ptr::copy_nonoverlapping; -use core::{result, str}; +use core::result; +use core::str; + #[cfg(feature = "std")] use std::ffi::{CStr, CString}; use crate::endian::Endian; -use crate::{error, Pread, Pwrite}; +use crate::error; /// A trait for measuring how large something is; for a byte sequence, it will be its length. pub trait MeasureWith { @@ -237,14 +240,18 @@ impl Default for StrCtx { impl StrCtx { pub fn len(&self) -> usize { - match self { + match *self { StrCtx::Delimiter(_) | StrCtx::DelimiterUntil(_, _) => 1, StrCtx::Length(_) => 0, } } pub fn is_empty(&self) -> bool { - matches!(self, StrCtx::Length(_)) + if let StrCtx::Length(_) = *self { + true + } else { + false + } } } @@ -260,7 +267,6 @@ pub trait FromCtx { /// `[u8]`), then you need to implement this trait /// /// ```rust -/// ##[cfg(feature = "std")] { /// use scroll::{self, ctx, Pread}; /// #[derive(Debug, PartialEq, Eq)] /// pub struct Foo(u16); @@ -280,7 +286,6 @@ pub trait FromCtx { /// /// let foo2 = bytes.pread_with::(0, scroll::BE).unwrap(); /// assert_eq!(Foo(0xdeadu16), foo2); -/// # } /// ``` /// /// # Advanced: Using Your Own Error in `TryFromCtx` @@ -345,7 +350,6 @@ pub trait IntoCtx: Sized { /// To implement writing into an arbitrary byte buffer, implement `TryIntoCtx` /// # Example /// ```rust -/// ##[cfg(feature = "std")] { /// use scroll::{self, ctx, LE, Endian, Pwrite}; /// #[derive(Debug, PartialEq, Eq)] /// pub struct Foo(u16); @@ -365,7 +369,6 @@ pub trait IntoCtx: Sized { /// /// let mut bytes: [u8; 4] = [0, 0, 0, 0]; /// bytes.pwrite_with(Foo(0x7f), 1, LE).unwrap(); -/// # } /// ``` pub trait TryIntoCtx: Sized { type Error; @@ -400,14 +403,13 @@ macro_rules! signed_to_unsigned { macro_rules! write_into { ($typ:ty, $size:expr, $n:expr, $dst:expr, $endian:expr) => {{ - assert!($dst.len() >= $size); - let bytes = if $endian.is_little() { - $n.to_le() - } else { - $n.to_be() - } - .to_ne_bytes(); unsafe { + assert!($dst.len() >= $size); + let bytes = transmute::<$typ, [u8; $size]>(if $endian.is_little() { + $n.to_le() + } else { + $n.to_be() + }); copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size); } }}; @@ -568,12 +570,12 @@ macro_rules! from_ctx_float_impl { &mut data as *mut signed_to_unsigned!($typ) as *mut u8, $size, ); + transmute(if le.is_little() { + data.to_le() + } else { + data.to_be() + }) } - $typ::from_bits(if le.is_little() { - data.to_le() - } else { - data.to_be() - }) } } impl<'a> TryFromCtx<'a, Endian> for $typ @@ -619,7 +621,13 @@ macro_rules! into_ctx_float_impl { #[inline] fn into_ctx(self, dst: &mut [u8], le: Endian) { assert!(dst.len() >= $size); - write_into!(signed_to_unsigned!($typ), $size, self.to_bits(), dst, le); + write_into!( + signed_to_unsigned!($typ), + $size, + transmute::<$typ, signed_to_unsigned!($typ)>(self), + dst, + le + ); } } impl<'a> IntoCtx for &'a $typ { @@ -717,7 +725,7 @@ impl<'a> TryIntoCtx for &'a [u8] { let src_len = self.len() as isize; let dst_len = dst.len() as isize; // if src_len < 0 || dst_len < 0 || offset < 0 { - // return Err(error::Error::BadOffset(format!("requested operation has negative casts: src len: {src_len} dst len: {dst_len} offset: {offset}")).into()) + // return Err(error::Error::BadOffset(format!("requested operation has negative casts: src len: {} dst len: {} offset: {}", src_len, dst_len, offset)).into()) // } if src_len > dst_len { Err(error::Error::TooBig { @@ -781,56 +789,6 @@ impl<'a> TryFromCtx<'a, usize> for &'a [u8] { } } -impl<'a, Ctx: Copy, T: TryFromCtx<'a, Ctx, Error = error::Error>, const N: usize> - TryFromCtx<'a, Ctx> for [T; N] -{ - type Error = error::Error; - fn try_from_ctx(src: &'a [u8], ctx: Ctx) -> Result<(Self, usize), Self::Error> { - let mut offset = 0; - - let mut buf: [MaybeUninit; N] = core::array::from_fn(|_| MaybeUninit::uninit()); - - let mut error_ctx = None; - for (idx, element) in buf.iter_mut().enumerate() { - match src.gread_with::(&mut offset, ctx) { - Ok(val) => { - *element = MaybeUninit::new(val); - } - Err(e) => { - error_ctx = Some((e, idx)); - break; - } - } - } - if let Some((e, idx)) = error_ctx { - for element in &mut buf[0..idx].iter_mut() { - // SAFETY: Any element upto idx must have already been initialized, since - // we iterate until we encounter an error. - unsafe { - element.assume_init_drop(); - } - } - Err(e) - } else { - // SAFETY: we initialized each element above by preading them out, correctness - // of the initialized element is guaranted by pread itself - Ok((buf.map(|element| unsafe { element.assume_init() }), offset)) - } - } -} -impl, const N: usize> TryIntoCtx - for [T; N] -{ - type Error = error::Error; - fn try_into_ctx(self, buf: &mut [u8], ctx: Ctx) -> Result { - let mut offset = 0; - for element in self { - buf.gwrite_with(element, &mut offset, ctx)?; - } - Ok(offset) - } -} - #[cfg(feature = "std")] impl<'a> TryFromCtx<'a> for &'a CStr { type Error = error::Error; @@ -905,11 +863,11 @@ impl TryIntoCtx for CString { // } #[cfg(test)] -#[cfg(feature = "std")] mod tests { use super::*; #[test] + #[cfg(feature = "std")] fn parse_a_cstr() { let src = CString::new("Hello World").unwrap(); let as_bytes = src.as_bytes_with_nul(); @@ -921,6 +879,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn round_trip_a_c_str() { let src = CString::new("Hello World").unwrap(); let src = src.as_c_str(); diff --git a/third_party/rust/scroll/src/endian.rs b/third_party/rust/scroll/src/endian.rs index 7b83c348d5fe..06d7a1dc1c0e 100644 --- a/third_party/rust/scroll/src/endian.rs +++ b/third_party/rust/scroll/src/endian.rs @@ -43,6 +43,9 @@ impl Endian { } #[inline] pub fn is_little(&self) -> bool { - *self == LE + match *self { + LE => true, + _ => false, + } } } diff --git a/third_party/rust/scroll/src/error.rs b/third_party/rust/scroll/src/error.rs index 1b68c2e4c730..774025477468 100644 --- a/third_party/rust/scroll/src/error.rs +++ b/third_party/rust/scroll/src/error.rs @@ -1,7 +1,10 @@ use core::fmt::{self, Display}; use core::result; + +#[cfg(feature = "std")] +use std::error; #[cfg(feature = "std")] -use std::{error, io}; +use std::io; #[derive(Debug)] /// A custom Scroll error @@ -17,19 +20,18 @@ pub enum Error { size: usize, msg: &'static str, }, - /// A custom Scroll error for reporting messages to clients. - /// For no-std, use [`Error::BadInput`] with a static string. #[cfg(feature = "std")] + /// A custom Scroll error for reporting messages to clients Custom(String), - /// Returned when IO based errors are encountered #[cfg(feature = "std")] + /// Returned when IO based errors are encountered IO(io::Error), } #[cfg(feature = "std")] impl error::Error for Error { fn description(&self) -> &str { - match self { + match *self { Error::TooBig { .. } => "TooBig", Error::BadOffset(_) => "BadOffset", Error::BadInput { .. } => "BadInput", @@ -38,7 +40,7 @@ impl error::Error for Error { } } fn cause(&self) -> Option<&dyn error::Error> { - match self { + match *self { Error::TooBig { .. } => None, Error::BadOffset(_) => None, Error::BadInput { .. } => None, @@ -57,23 +59,23 @@ impl From for Error { impl Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { + match *self { Error::TooBig { ref size, ref len } => { - write!(fmt, "type is too big ({size}) for {len}") + write!(fmt, "type is too big ({}) for {}", size, len) } Error::BadOffset(ref offset) => { - write!(fmt, "bad offset {offset}") + write!(fmt, "bad offset {}", offset) } Error::BadInput { ref msg, ref size } => { - write!(fmt, "bad input {msg} ({size})") + write!(fmt, "bad input {} ({})", msg, size) } #[cfg(feature = "std")] Error::Custom(ref msg) => { - write!(fmt, "{msg}") + write!(fmt, "{}", msg) } #[cfg(feature = "std")] Error::IO(ref err) => { - write!(fmt, "{err}") + write!(fmt, "{}", err) } } } diff --git a/third_party/rust/scroll/src/leb128.rs b/third_party/rust/scroll/src/leb128.rs index eceec6d16613..43f50b95f176 100644 --- a/third_party/rust/scroll/src/leb128.rs +++ b/third_party/rust/scroll/src/leb128.rs @@ -1,8 +1,9 @@ -use core::convert::{AsRef, From}; -use core::{result, u8}; - use crate::ctx::TryFromCtx; -use crate::{error, Pread}; +use crate::error; +use crate::Pread; +use core::convert::{AsRef, From}; +use core::result; +use core::u8; #[derive(Debug, PartialEq, Copy, Clone)] /// An unsigned leb128 integer @@ -183,24 +184,21 @@ mod tests { let buf = [2u8 | CONTINUATION_BIT, 1]; let bytes = &buf[..]; let num = bytes.pread::(0).unwrap(); - #[cfg(feature = "std")] - println!("num: {num:?}"); + println!("num: {:?}", &num); assert_eq!(130u64, num.into()); assert_eq!(num.size(), 2); let buf = [0x00, 0x01]; let bytes = &buf[..]; let num = bytes.pread::(0).unwrap(); - #[cfg(feature = "std")] - println!("num: {num:?}"); + println!("num: {:?}", &num); assert_eq!(0u64, num.into()); assert_eq!(num.size(), 1); let buf = [0x21]; let bytes = &buf[..]; let num = bytes.pread::(0).unwrap(); - #[cfg(feature = "std")] - println!("num: {num:?}"); + println!("num: {:?}", &num); assert_eq!(0x21u64, num.into()); assert_eq!(num.size(), 1); } diff --git a/third_party/rust/scroll/src/lesser.rs b/third_party/rust/scroll/src/lesser.rs index 636bf2553e79..46ef4c5b11a5 100644 --- a/third_party/rust/scroll/src/lesser.rs +++ b/third_party/rust/scroll/src/lesser.rs @@ -1,6 +1,5 @@ -use std::io::{Read, Result, Write}; - use crate::ctx::{FromCtx, IntoCtx, SizeWith}; +use std::io::{Read, Result, Write}; /// An extension trait to `std::io::Read` streams; mainly targeted at reading primitive types with /// a known size. @@ -105,8 +104,8 @@ pub trait IOread: Read { fn ioread_with + SizeWith>(&mut self, ctx: Ctx) -> Result { let mut scratch = [0u8; 256]; let size = N::size_with(&ctx); - let buf = &mut scratch[0..size]; - self.read_exact(buf)?; + let mut buf = &mut scratch[0..size]; + self.read_exact(&mut buf)?; Ok(N::from_ctx(buf, ctx)) } } diff --git a/third_party/rust/scroll/src/lib.rs b/third_party/rust/scroll/src/lib.rs index 27406485174a..dcb58e7564f6 100644 --- a/third_party/rust/scroll/src/lib.rs +++ b/third_party/rust/scroll/src/lib.rs @@ -119,7 +119,6 @@ //! [FromCtx](ctx/trait.FromCtx.html) and [SizeWith](ctx/trait.SizeWith.html). //! //! ```rust -//! ##[cfg(feature = "std")] { //! use std::io::Cursor; //! use scroll::{IOread, ctx, Endian}; //! let bytes = [0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xef,0xbe,0x00,0x00,]; @@ -140,14 +139,12 @@ //! // read/written, e.g. switching between ELF32 or ELF64 at runtime. //! let size = >::size_with(&Endian::Little) as u64; //! assert_eq!(prev + size, after); -//! # } //! ``` //! //! In the same vein as IOread we can use IOwrite to write a type to anything implementing //! `std::io::Write`: //! //! ```rust -//! ##[cfg(feature = "std")] { //! use std::io::Cursor; //! use scroll::{IOwrite}; //! @@ -158,7 +155,6 @@ //! cursor.iowrite_with(0xdeadbeef as u32, scroll::BE).unwrap(); //! //! assert_eq!(cursor.into_inner(), [0xde, 0xad, 0xbe, 0xef, 0x0]); -//! # } //! ``` //! //! ## Complex use cases @@ -253,7 +249,8 @@ pub use crate::pwrite::*; #[doc(hidden)] pub mod export { - pub use ::core::{mem, result}; + pub use ::core::mem; + pub use ::core::result; } #[allow(unused)] @@ -270,6 +267,7 @@ doc_comment!(include_str!("../README.md")); #[cfg(test)] mod tests { + #[allow(overflowing_literals)] use super::LE; #[test] @@ -357,48 +355,36 @@ mod tests { let bytes: [u8; 2] = [0x2e, 0x0]; let b = &bytes[..]; let s: &str = b.pread(0).unwrap(); - #[cfg(feature = "std")] - println!("str: {s}"); + println!("str: {}", s); assert_eq!(s.len(), bytes[..].len() - 1); let bytes: &[u8] = b"hello, world!\0some_other_things"; let hello_world: &str = bytes.pread_with(0, StrCtx::Delimiter(NULL)).unwrap(); - #[cfg(feature = "std")] - println!("{hello_world:?}"); + println!("{:?}", &hello_world); assert_eq!(hello_world.len(), 13); let hello: &str = bytes.pread_with(0, StrCtx::Delimiter(SPACE)).unwrap(); - #[cfg(feature = "std")] - println!("{hello:?}"); + println!("{:?}", &hello); assert_eq!(hello.len(), 6); // this could result in underflow so we just try it let _error = bytes.pread_with::<&str>(6, StrCtx::Delimiter(SPACE)); let error = bytes.pread_with::<&str>(7, StrCtx::Delimiter(SPACE)); - #[cfg(feature = "std")] - println!("{error:?}"); + println!("{:?}", &error); assert!(error.is_ok()); } - /// In this test, we are testing preading - /// at length boundaries. - /// In the past, this test was supposed to test failures for `hello_world`. - /// Since PR#94, this test is unwrapping as we exploit - /// the fact that if you do &x[x.len()..] you get an empty slice. #[test] fn pread_str_weird() { use super::ctx::*; use super::Pread; let bytes: &[u8] = b""; let hello_world = bytes.pread_with::<&str>(0, StrCtx::Delimiter(NULL)); - #[cfg(feature = "std")] - println!("1 {hello_world:?}"); - assert!(hello_world.unwrap().is_empty()); + println!("1 {:?}", &hello_world); + assert_eq!(hello_world.is_err(), true); let error = bytes.pread_with::<&str>(7, StrCtx::Delimiter(SPACE)); - #[cfg(feature = "std")] - println!("2 {error:?}"); + println!("2 {:?}", &error); assert!(error.is_err()); let bytes: &[u8] = b"\0"; let null = bytes.pread::<&str>(0).unwrap(); - #[cfg(feature = "std")] - println!("3 {null:?}"); + println!("3 {:?}", &null); assert_eq!(null.len(), 0); } @@ -427,7 +413,8 @@ mod tests { assert_eq!(bytes, "bytes"); } - use core::fmt::{self, Display}; + use std::error; + use std::fmt::{self, Display}; #[derive(Debug)] pub struct ExternalError {} @@ -438,12 +425,11 @@ mod tests { } } - #[cfg(feature = "std")] - impl std::error::Error for ExternalError { + impl error::Error for ExternalError { fn description(&self) -> &str { "ExternalError" } - fn cause(&self) -> Option<&dyn std::error::Error> { + fn cause(&self) -> Option<&dyn error::Error> { None } } @@ -465,7 +451,7 @@ mod tests { fn try_into_ctx(self, this: &mut [u8], le: super::Endian) -> Result { use super::Pwrite; if this.len() < 2 { - return Err(ExternalError {}); + return Err((ExternalError {}).into()); } this.pwrite_with(self.0, 0, le)?; Ok(2) @@ -477,7 +463,7 @@ mod tests { fn try_from_ctx(this: &'a [u8], le: super::Endian) -> Result<(Self, usize), Self::Error> { use super::Pread; if this.len() > 2 { - return Err(ExternalError {}); + return Err((ExternalError {}).into()); } let n = this.pread_with(0, le)?; Ok((Foo(n), 2)) @@ -513,7 +499,7 @@ mod tests { let mut offset = 0; let deadbeef: $typ = bytes.gread_with(&mut offset, LE).unwrap(); assert_eq!(deadbeef, $deadbeef as $typ); - assert_eq!(offset, ::core::mem::size_of::<$typ>()); + assert_eq!(offset, ::std::mem::size_of::<$typ>()); } }; } @@ -532,7 +518,7 @@ mod tests { let mut offset = 0; let deadbeef: $typ = bytes.gread_with(&mut offset, LE).unwrap(); assert_eq!(deadbeef, $deadbeef as $typ); - assert_eq!(offset, ::core::mem::size_of::<$typ>()); + assert_eq!(offset, ::std::mem::size_of::<$typ>()); } }; } @@ -551,8 +537,8 @@ mod tests { let o2 = &mut 0; let val: $typ = buffer.gread_with(o2, LE).unwrap(); assert_eq!(val, $val); - assert_eq!(*offset, ::core::mem::size_of::<$typ>()); - assert_eq!(*o2, ::core::mem::size_of::<$typ>()); + assert_eq!(*offset, ::std::mem::size_of::<$typ>()); + assert_eq!(*o2, ::std::mem::size_of::<$typ>()); assert_eq!(*o2, *offset); buffer.gwrite_with($val.clone(), offset, BE).unwrap(); let val: $typ = buffer.gread_with(o2, BE).unwrap(); @@ -626,17 +612,16 @@ mod tests { let res = b.gread_with::<&str>(offset, StrCtx::Length(3)); assert!(res.is_err()); *offset = 0; - let astring: [u8; 3] = [0x45, 0x42, 0x44]; + let astring: [u8; 3] = [0x45, 042, 0x44]; let string = astring.gread_with::<&str>(offset, StrCtx::Length(2)); match &string { - Ok(_) => {} - Err(_err) => { - #[cfg(feature = "std")] - println!("{_err}"); + &Ok(_) => {} + &Err(ref err) => { + println!("{}", &err); panic!(); } } - assert_eq!(string.unwrap(), "EB"); + assert_eq!(string.unwrap(), "E*"); *offset = 0; let bytes2: &[u8] = b.gread_with(offset, 2).unwrap(); assert_eq!(*offset, 2); diff --git a/third_party/rust/scroll/src/pread.rs b/third_party/rust/scroll/src/pread.rs index 15bf1426be3f..72ba87705444 100644 --- a/third_party/rust/scroll/src/pread.rs +++ b/third_party/rust/scroll/src/pread.rs @@ -20,11 +20,6 @@ use crate::error; /// over chunks of memory or any other indexable type — but scroll does come with a set of powerful /// blanket implementations for data being a continous block of byte-addressable memory. /// -/// Note that in the particular case of the implementation of `Pread` for `[u8]`, -/// reading it at the length boundary of that slice will cause to read from an empty slice. -/// i.e. we make use of the fact that `&bytes[bytes.len()..]` will return an empty slice, rather -/// than returning an error. In the past, scroll returned an offset error. -/// /// Pread provides two main groups of functions: pread and gread. /// /// `pread` is the basic function that simply extracts a given type from a given data store - either @@ -172,7 +167,7 @@ impl> Pread for [u8] { ctx: Ctx, ) -> result::Result { let start = *offset; - if start > self.len() { + if start >= self.len() { return Err(error::Error::BadOffset(start).into()); } N::try_from_ctx(&self[start..], ctx).map(|(n, size)| { diff --git a/third_party/rust/scroll/src/pwrite.rs b/third_party/rust/scroll/src/pwrite.rs index 7a07f2dabaa7..ab6d96157d46 100644 --- a/third_party/rust/scroll/src/pwrite.rs +++ b/third_party/rust/scroll/src/pwrite.rs @@ -19,13 +19,6 @@ use crate::error; /// with 'read' switched for 'write' and 'From' switched with 'Into' so if you haven't yet you /// should read the documentation of `Pread` first. /// -/// As with `Pread`, note that in the particular case of the implementation of `Pwrite` for `[u8]`, -/// writing it at the length boundary of that slice will cause to write in an empty slice. -/// i.e. we make use of the fact that `&bytes[bytes.len()..]` will return an empty slice, rather -/// than returning an error. In the past, scroll returned an offset error. -/// In this case, this is relevant if you are writing an empty slice inside an empty slice and -/// expected this to work. -/// /// Unless you need to implement your own data store — that is either can't convert to `&[u8]` or /// have a data that does not expose a `&mut [u8]` — you will probably want to implement /// [TryIntoCtx](ctx/trait.TryIntoCtx.html) on your Rust types to be written. @@ -94,7 +87,7 @@ impl> Pwrite for [u8] { offset: usize, ctx: Ctx, ) -> result::Result { - if offset > self.len() { + if offset >= self.len() { return Err(error::Error::BadOffset(offset).into()); } let dst = &mut self[offset..]; diff --git a/third_party/rust/scroll/tests/api.rs b/third_party/rust/scroll/tests/api.rs new file mode 100644 index 000000000000..e10726f22a20 --- /dev/null +++ b/third_party/rust/scroll/tests/api.rs @@ -0,0 +1,292 @@ +// this exists primarily to test various API usages of scroll; e.g., must compile + +// guard against potential undefined behaviour when borrowing from +// packed structs. See https://github.com/rust-lang/rust/issues/46043 +#![deny(unaligned_references)] + +// #[macro_use] extern crate scroll_derive; + +use scroll::ctx::SizeWith; +use scroll::{ctx, Cread, Pread, Result}; +use std::ops::{Deref, DerefMut}; + +#[derive(Default)] +pub struct Section<'a> { + pub sectname: [u8; 16], + pub segname: [u8; 16], + pub addr: u64, + pub size: u64, + pub offset: u32, + pub align: u32, + pub reloff: u32, + pub nreloc: u32, + pub flags: u32, + pub data: &'a [u8], +} + +impl<'a> Section<'a> { + pub fn name(&self) -> Result<&str> { + self.sectname.pread::<&str>(0) + } + pub fn segname(&self) -> Result<&str> { + self.segname.pread::<&str>(0) + } +} + +impl<'a> ctx::SizeWith for Section<'a> { + fn size_with(_ctx: &()) -> usize { + 4 + } +} + +#[repr(C)] +// renable when scroll_derive Pread/Pwrite matches +//#[derive(Debug, Clone, Copy, Pread, Pwrite)] +#[derive(Debug, Clone, Copy)] +pub struct Section32 { + pub sectname: [u8; 16], + pub segname: [u8; 16], + pub addr: u32, + pub size: u32, + pub offset: u32, + pub align: u32, + pub reloff: u32, + pub nreloc: u32, + pub flags: u32, + pub reserved1: u32, + pub reserved2: u32, +} + +impl<'a> ctx::TryFromCtx<'a, ()> for Section<'a> { + type Error = scroll::Error; + fn try_from_ctx( + _bytes: &'a [u8], + _ctx: (), + ) -> ::std::result::Result<(Self, usize), Self::Error> { + let section = Section::default(); + Ok((section, ::std::mem::size_of::
())) + } +} + +pub struct Segment<'a> { + pub cmd: u32, + pub cmdsize: u32, + pub segname: [u8; 16], + pub vmaddr: u64, + pub vmsize: u64, + pub fileoff: u64, + pub filesize: u64, + pub maxprot: u32, + pub initprot: u32, + pub nsects: u32, + pub flags: u32, + pub data: &'a [u8], + offset: usize, + raw_data: &'a [u8], +} + +impl<'a> Segment<'a> { + pub fn name(&self) -> Result<&str> { + Ok(self.segname.pread::<&str>(0)?) + } + pub fn sections(&self) -> Result>> { + let nsects = self.nsects as usize; + let mut sections = Vec::with_capacity(nsects); + let offset = &mut (self.offset + Self::size_with(&())); + let _size = Section::size_with(&()); + let raw_data: &'a [u8] = self.raw_data; + for _ in 0..nsects { + let section = raw_data.gread_with::>(offset, ())?; + sections.push(section); + //offset += size; + } + Ok(sections) + } +} + +impl<'a> ctx::SizeWith for Segment<'a> { + fn size_with(_ctx: &()) -> usize { + 4 + } +} + +pub struct Segments<'a> { + pub segments: Vec>, +} + +impl<'a> Deref for Segments<'a> { + type Target = Vec>; + fn deref(&self) -> &Self::Target { + &self.segments + } +} + +impl<'a> DerefMut for Segments<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.segments + } +} + +impl<'a> Segments<'a> { + pub fn new() -> Self { + Segments { + segments: Vec::new(), + } + } + pub fn sections(&self) -> Result>>> { + let mut sections = Vec::new(); + for segment in &self.segments { + sections.push(segment.sections()?); + } + Ok(sections) + } +} + +fn lifetime_passthrough_<'a>(segments: &Segments<'a>, section_name: &str) -> Option<&'a [u8]> { + let segment_name = "__TEXT"; + for segment in &segments.segments { + if let Ok(name) = segment.name() { + println!("segment.name: {}", name); + if name == segment_name { + if let Ok(sections) = segment.sections() { + for section in sections { + let sname = section.name().unwrap(); + println!("section.name: {}", sname); + if section_name == sname { + return Some(section.data); + } + } + } + } + } + } + None +} + +#[test] +fn lifetime_passthrough() { + let segments = Segments::new(); + let _res = lifetime_passthrough_(&segments, "__text"); + assert!(true) +} + +#[derive(Default)] +#[repr(packed)] +struct Foo { + foo: i64, + bar: u32, +} + +impl scroll::ctx::FromCtx for Foo { + fn from_ctx(bytes: &[u8], ctx: scroll::Endian) -> Self { + Foo { + foo: bytes.cread_with::(0, ctx), + bar: bytes.cread_with::(8, ctx), + } + } +} + +impl scroll::ctx::SizeWith for Foo { + fn size_with(_: &scroll::Endian) -> usize { + ::std::mem::size_of::() + } +} + +#[test] +fn ioread_api() { + use scroll::{IOread, LE}; + use std::io::Cursor; + let bytes_ = [ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xbe, 0x00, 0x00, + ]; + let mut bytes = Cursor::new(bytes_); + let foo = bytes.ioread_with::(LE).unwrap(); + let bar = bytes.ioread_with::(LE).unwrap(); + assert_eq!(foo, 1); + assert_eq!(bar, 0xbeef); + let error = bytes.ioread_with::(LE); + assert!(error.is_err()); + let mut bytes = Cursor::new(bytes_); + let foo_ = bytes.ioread_with::(LE).unwrap(); + assert_eq!({ foo_.foo }, foo); + assert_eq!({ foo_.bar }, bar); +} + +#[repr(packed)] +struct Bar { + foo: i32, + bar: u32, +} + +impl scroll::ctx::FromCtx for Bar { + fn from_ctx(bytes: &[u8], ctx: scroll::Endian) -> Self { + Bar { + foo: bytes.cread_with(0, ctx), + bar: bytes.cread_with(4, ctx), + } + } +} + +#[test] +fn cread_api() { + use scroll::{Cread, LE}; + let bytes = [ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xbe, 0x00, 0x00, + ]; + let foo = bytes.cread_with::(0, LE); + let bar = bytes.cread_with::(8, LE); + assert_eq!(foo, 1); + assert_eq!(bar, 0xbeef); +} + +#[test] +fn cread_api_customtype() { + use scroll::{Cread, LE}; + let bytes = [0xff, 0xff, 0xff, 0xff, 0xef, 0xbe, 0xad, 0xde]; + let bar = &bytes[..].cread_with::(0, LE); + assert_eq!({ bar.foo }, -1); + assert_eq!({ bar.bar }, 0xdeadbeef); +} + +#[test] +#[should_panic] +fn cread_api_badindex() { + use scroll::Cread; + let bytes = [ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0xbe, 0xad, 0xde, + ]; + let _foo = bytes.cread::(1_000_000); +} + +#[test] +fn cwrite_api() { + use scroll::Cread; + use scroll::Cwrite; + let mut bytes = [0x0; 16]; + bytes.cwrite::(42, 0); + bytes.cwrite::(0xdeadbeef, 8); + assert_eq!(bytes.cread::(0), 42); + assert_eq!(bytes.cread::(8), 0xdeadbeef); +} + +impl scroll::ctx::IntoCtx for Bar { + fn into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) { + use scroll::Cwrite; + bytes.cwrite_with(self.foo, 0, ctx); + bytes.cwrite_with(self.bar, 4, ctx); + } +} + +#[test] +fn cwrite_api_customtype() { + use scroll::{Cread, Cwrite}; + let bar = Bar { + foo: -1, + bar: 0xdeadbeef, + }; + let mut bytes = [0x0; 16]; + let _ = &bytes[..].cwrite::(bar, 0); + let bar = bytes.cread::(0); + assert_eq!({ bar.foo }, -1); + assert_eq!({ bar.bar }, 0xdeadbeef); +} diff --git a/third_party/rust/scroll_derive/.cargo-checksum.json b/third_party/rust/scroll_derive/.cargo-checksum.json dissimilarity index 84% index b881da6c6a80..8c6b3b87c4fe 100644 --- a/third_party/rust/scroll_derive/.cargo-checksum.json +++ b/third_party/rust/scroll_derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"57ee02784903ef6f506e87164230e0bf543cf9f9bcd1546e123158c7ab98b648","LICENSE":"afb11426e09da40a1ae4f8fa17ddcc6b6a52d14df04c29bc5bcd06eb8730624d","README.md":"0ed9b8c8ec7dd75f14aab9b7e54769f81b86e68960658356e260e5ec8ccac206","src/lib.rs":"a9cabe3c0b373f352357745b817f188ab841e9445056014dee9cc83c4d167483"},"package":"7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932"} \ No newline at end of file +{"files":{"Cargo.toml":"9fbb5068c3ffbf2c357f4068f854f439bae4999e04527e2dedc6758fa37a9807","LICENSE":"afb11426e09da40a1ae4f8fa17ddcc6b6a52d14df04c29bc5bcd06eb8730624d","README.md":"f89c7768454b0d2b9db816afe05db3a4cea1125bef87f08ed3eefd65e9e2b180","src/lib.rs":"a9cabe3c0b373f352357745b817f188ab841e9445056014dee9cc83c4d167483"},"package":"1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae"} \ No newline at end of file diff --git a/third_party/rust/scroll_derive/Cargo.toml b/third_party/rust/scroll_derive/Cargo.toml index 9e2e33bd78cf..71f40a7e6c97 100644 --- a/third_party/rust/scroll_derive/Cargo.toml +++ b/third_party/rust/scroll_derive/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "scroll_derive" -version = "0.12.0" +version = "0.11.1" authors = [ "m4b ", "Ted Mielczarek ", diff --git a/third_party/rust/scroll_derive/README.md b/third_party/rust/scroll_derive/README.md index 675b6d780335..a7f7e85f0e7d 100644 --- a/third_party/rust/scroll_derive/README.md +++ b/third_party/rust/scroll_derive/README.md @@ -21,7 +21,7 @@ use scroll::{Pread, Pwrite, Cread, LE}; fn main (){ let bytes = [0xefu8, 0xbe, 0xad, 0xde, 0, 0, 0, 0, 0, 0, 224, 63, 0xad, 0xde, 0xef, 0xbe]; let data: Data = bytes.pread_with(0, LE).unwrap(); - println!("data: {data:?}"); + println!("data: {:?}", &data); assert_eq!(data.id, 0xdeadbeefu32); let mut bytes2 = vec![0; ::std::mem::size_of::()]; bytes2.pwrite_with(data, 0, LE).unwrap(); diff --git a/third_party/rust/smawk/.cargo-checksum.json b/third_party/rust/smawk/.cargo-checksum.json deleted file mode 100644 index c553a4a2c69d..000000000000 --- a/third_party/rust/smawk/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"4581638d3c628d22826bde37114048c825ffb354f17f21645d8d49f9ebd64689","LICENSE":"0173035e025d60b1d19197840a93a887f6da8b075c01dd10601fcb6414a0043b","README.md":"c27297df61be8dd14e47dc30a80ae1d443f5acea82932139637543bc6d860631","dprint.json":"aacd5ec32db8741fbdea4ac916e61f0011485a51e8ec7a660f849be60cc7b512","rustfmt.toml":"6819baea67831b8a8b2a7ad33af1128dd2774a900c804635c912bb6545a4e922","src/brute_force.rs":"02edda18441ea5d6cc89d2fdfb9ab32a361e2598de74a71fb930fb630288ce35","src/lib.rs":"b312e4855945cfe27f4b1e9949b1c6ffea8f248ad80ac8fc49e72f0cc38df219","src/monge.rs":"f6c475f4d094b70b5e45d0c8a94112d42eaafa0ab41b2d3d96d06a38f1bac32d","src/recursive.rs":"e585286fe6c885dcac8001d0f484718aa8f73f3f85a452f8b4c1cb36d4fbfcf6","tests/agreement.rs":"764406a5d8c9a322bab8787764d780832cfc3962722ed01efda99684a619d543","tests/complexity.rs":"e2e850d38529f171eb6005807c2a86a3f95a907052253eaa8e24a834200cda0b","tests/monge.rs":"fe418373f89904cd40e2ed1d539bccd2d9be50c1f3f9ab2d93806ff3bce6b7ea","tests/random_monge/mod.rs":"83cf1dd0c7b0b511ad754c19857a5d830ed54e8fef3c31235cd70b709687534b","tests/version-numbers.rs":"73301b7bfe500eada5ede66f0dce89bd3e354af50a8e7a123b02931cd5eb8e16"},"package":"b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"} \ No newline at end of file diff --git a/third_party/rust/smawk/Cargo.toml b/third_party/rust/smawk/Cargo.toml deleted file mode 100644 index 44fc03df3099..000000000000 --- a/third_party/rust/smawk/Cargo.toml +++ /dev/null @@ -1,53 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -name = "smawk" -version = "0.3.2" -authors = ["Martin Geisler "] -exclude = [ - ".github/", - ".gitignore", - "benches/", - "examples/", -] -description = "Functions for finding row-minima in a totally monotone matrix." -readme = "README.md" -keywords = [ - "smawk", - "matrix", - "optimization", - "dynamic-programming", -] -categories = [ - "algorithms", - "mathematics", - "science", -] -license = "MIT" -repository = "https://github.com/mgeisler/smawk" - -[dependencies.ndarray] -version = "0.15.4" -optional = true - -[dev-dependencies.num-traits] -version = "0.2.14" - -[dev-dependencies.rand] -version = "0.8.4" - -[dev-dependencies.rand_chacha] -version = "0.3.1" - -[dev-dependencies.version-sync] -version = "0.9.4" diff --git a/third_party/rust/smawk/LICENSE b/third_party/rust/smawk/LICENSE deleted file mode 100644 index 124067f7aee7..000000000000 --- a/third_party/rust/smawk/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Martin Geisler - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/third_party/rust/smawk/README.md b/third_party/rust/smawk/README.md deleted file mode 100644 index 7d45acfeef37..000000000000 --- a/third_party/rust/smawk/README.md +++ /dev/null @@ -1,151 +0,0 @@ -# SMAWK Algorithm in Rust - -[![](https://github.com/mgeisler/smawk/workflows/build/badge.svg)][build-status] -[![](https://codecov.io/gh/mgeisler/smawk/branch/master/graph/badge.svg)][codecov] -[![](https://img.shields.io/crates/v/smawk.svg)][crates-io] -[![](https://docs.rs/smawk/badge.svg)][api-docs] - -This crate contains an implementation of the [SMAWK algorithm][smawk] for -finding the smallest element per row in a totally monotone matrix. - -The SMAWK algorithm allows you to lower the running time of some algorithms from -O(_n_²) to just O(_n_). In other words, you can turn a quadratic time complexity -(which is often too expensive) into linear time complexity. - -Finding optimal line breaks in a paragraph of text is an example of an algorithm -which would normally take O(_n_²) time for _n_ words. With this crate, the -running time becomes linear. Please see the [textwrap crate][textwrap] for an -example of this. - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -smawk = "0.3" -``` - -You can now efficiently find row and column minima. Here is an example where we -find the column minima: - -```rust -use smawk::Matrix; - -let matrix = vec![ - vec![3, 2, 4, 5, 6], - vec![2, 1, 3, 3, 4], - vec![2, 1, 3, 3, 4], - vec![3, 2, 4, 3, 4], - vec![4, 3, 2, 1, 1], -]; -let minima = vec![1, 1, 4, 4, 4]; -assert_eq!(smawk::column_minima(&matrix), minima); -``` - -The `minima` vector gives the index of the minimum value per column, so -`minima[0] == 1` since the minimum value in the first column is 2 (row 1). Note -that the smallest row index is returned. - -### Cargo Features - -This crate has an optional dependency on the -[`ndarray` crate](https://docs.rs/ndarray/), which provides an efficient matrix -implementation. Enable the `ndarray` Cargo feature to use it. - -## Documentation - -**[API documentation][api-docs]** - -## Changelog - -### Version 0.3.2 (2023-09-17) - -This release adds more documentation and renames the top-level SMAWK functions. -The old names have been kept for now to ensure backwards compatibility, but they -will be removed in a future release. - -- [#65](https://github.com/mgeisler/smawk/pull/65): Forbid the use of unsafe - code. -- [#69](https://github.com/mgeisler/smawk/pull/69): Migrate to the Rust 2021 - edition. -- [#73](https://github.com/mgeisler/smawk/pull/73): Add examples to all - functions. -- [#74](https://github.com/mgeisler/smawk/pull/74): Add “mathematics” as a crate - category. -- [#75](https://github.com/mgeisler/smawk/pull/75): Remove `smawk_` prefix from - optimized functions. - -### Version 0.3.1 (2021-01-30) - -This release relaxes the bounds on the `smawk_row_minima`, -`smawk_column_minima`, and `online_column_minima` functions so that they work on -matrices containing floating point numbers. - -- [#55](https://github.com/mgeisler/smawk/pull/55): Relax bounds to `PartialOrd` - instead of `Ord`. -- [#56](https://github.com/mgeisler/smawk/pull/56): Update dependencies to their - latest versions. -- [#59](https://github.com/mgeisler/smawk/pull/59): Give an example of what - SMAWK does in the README. - -### Version 0.3.0 (2020-09-02) - -This release slims down the crate significantly by making `ndarray` an optional -dependency. - -- [#45](https://github.com/mgeisler/smawk/pull/45): Move non-SMAWK code and unit - tests out of lib and into separate modules. -- [#46](https://github.com/mgeisler/smawk/pull/46): Switch `smawk_row_minima` - and `smawk_column_minima` functions to a new `Matrix` trait. -- [#47](https://github.com/mgeisler/smawk/pull/47): Make the dependency on the - `ndarray` crate optional. -- [#48](https://github.com/mgeisler/smawk/pull/48): Let `is_monge` take a - `Matrix` argument instead of `ndarray::Array2`. -- [#50](https://github.com/mgeisler/smawk/pull/50): Remove mandatory - dependencies on `rand` and `num-traits` crates. - -### Version 0.2.0 (2020-07-29) - -This release updates the code to Rust 2018. - -- [#18](https://github.com/mgeisler/smawk/pull/18): Make `online_column_minima` - generic in matrix type. -- [#23](https://github.com/mgeisler/smawk/pull/23): Switch to the - [Rust 2018][rust-2018] edition. We test against the latest stable and nightly - version of Rust. -- [#29](https://github.com/mgeisler/smawk/pull/29): Drop strict Rust 2018 - compatibility by not testing with Rust 1.31.0. -- [#32](https://github.com/mgeisler/smawk/pull/32): Fix crash on overflow in - `is_monge`. -- [#33](https://github.com/mgeisler/smawk/pull/33): Update `rand` dependency to - latest version and get rid of `rand_derive`. -- [#34](https://github.com/mgeisler/smawk/pull/34): Bump `num-traits` and - `version-sync` dependencies to latest versions. -- [#35](https://github.com/mgeisler/smawk/pull/35): Drop unnecessary Windows - tests. The assumption is that the numeric computations we do are - cross-platform. -- [#36](https://github.com/mgeisler/smawk/pull/36): Update `ndarray` dependency - to the latest version. -- [#37](https://github.com/mgeisler/smawk/pull/37): Automate publishing new - releases to crates.io. - -### Version 0.1.0 — August 7th, 2018 - -First release with the classical offline SMAWK algorithm as well as a newer -online version where the matrix entries can depend on previously computed column -minima. - -## License - -SMAWK can be distributed according to the [MIT license][mit]. Contributions will -be accepted under the same license. - -[build-status]: https://github.com/mgeisler/smawk/actions?query=branch%3Amaster+workflow%3Abuild -[crates-io]: https://crates.io/crates/smawk -[codecov]: https://codecov.io/gh/mgeisler/smawk -[textwrap]: https://crates.io/crates/textwrap -[smawk]: https://en.wikipedia.org/wiki/SMAWK_algorithm -[api-docs]: https://docs.rs/smawk/ -[rust-2018]: https://doc.rust-lang.org/edition-guide/rust-2018/ -[mit]: LICENSE diff --git a/third_party/rust/smawk/dprint.json b/third_party/rust/smawk/dprint.json deleted file mode 100644 index e48af5fe9dc6..000000000000 --- a/third_party/rust/smawk/dprint.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "markdown": { - "textWrap": "always" - }, - "exec": { - "commands": [{ - "command": "rustfmt", - "exts": ["rs"] - }] - }, - "excludes": ["target/"], - "plugins": [ - "https://plugins.dprint.dev/json-0.17.4.wasm", - "https://plugins.dprint.dev/markdown-0.16.1.wasm", - "https://plugins.dprint.dev/toml-0.5.4.wasm", - "https://plugins.dprint.dev/exec-0.4.3.json@42343548b8022c99b1d750be6b894fe6b6c7ee25f72ae9f9082226dd2e515072", - "https://plugins.dprint.dev/prettier-0.27.0.json@3557a62b4507c55a47d8cde0683195b14d13c41dda66d0f0b0e111aed107e2fe" - ] -} diff --git a/third_party/rust/smawk/rustfmt.toml b/third_party/rust/smawk/rustfmt.toml deleted file mode 100644 index 24e4ea784ecd..000000000000 --- a/third_party/rust/smawk/rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -# Use rustfmt from the nightly channel for this: -imports_granularity = "Module" diff --git a/third_party/rust/smawk/src/brute_force.rs b/third_party/rust/smawk/src/brute_force.rs deleted file mode 100644 index 1ec0ca35a755..000000000000 --- a/third_party/rust/smawk/src/brute_force.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! Brute-force algorithm for finding column minima. -//! -//! The functions here are mostly meant to be used for testing -//! correctness of the SMAWK implementation. -//! -//! **Note: this module is only available if you enable the `ndarray` -//! Cargo feature.** - -use ndarray::{Array2, ArrayView1}; - -/// Compute lane minimum by brute force. -/// -/// This does a simple scan through the lane (row or column). -#[inline] -pub fn lane_minimum(lane: ArrayView1<'_, T>) -> usize { - lane.iter() - .enumerate() - .min_by_key(|&(idx, elem)| (elem, idx)) - .map(|(idx, _)| idx) - .expect("empty lane in matrix") -} - -/// Compute row minima by brute force in O(*mn*) time. -/// -/// This function implements a simple brute-force approach where each -/// matrix row is scanned completely. This means that the function -/// works on all matrices, not just Monge matrices. -/// -/// # Examples -/// -/// ``` -/// let matrix = ndarray::arr2(&[[4, 2, 4, 3], -/// [5, 3, 5, 3], -/// [5, 3, 3, 1]]); -/// assert_eq!(smawk::brute_force::row_minima(&matrix), -/// vec![1, 1, 3]); -/// ``` -/// -/// # Panics -/// -/// It is an error to call this on a matrix with zero columns. -pub fn row_minima(matrix: &Array2) -> Vec { - matrix.rows().into_iter().map(lane_minimum).collect() -} - -/// Compute column minima by brute force in O(*mn*) time. -/// -/// This function implements a simple brute-force approach where each -/// matrix column is scanned completely. This means that the function -/// works on all matrices, not just Monge matrices. -/// -/// # Examples -/// -/// ``` -/// let matrix = ndarray::arr2(&[[4, 2, 4, 3], -/// [5, 3, 5, 3], -/// [5, 3, 3, 1]]); -/// assert_eq!(smawk::brute_force::column_minima(&matrix), -/// vec![0, 0, 2, 2]); -/// ``` -/// -/// # Panics -/// -/// It is an error to call this on a matrix with zero rows. -pub fn column_minima(matrix: &Array2) -> Vec { - matrix.columns().into_iter().map(lane_minimum).collect() -} - -#[cfg(test)] -mod tests { - use super::*; - use ndarray::arr2; - - #[test] - fn brute_force_1x1() { - let matrix = arr2(&[[2]]); - let minima = vec![0]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn brute_force_2x1() { - let matrix = arr2(&[ - [3], // - [2], - ]); - let minima = vec![0, 0]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn brute_force_1x2() { - let matrix = arr2(&[[2, 1]]); - let minima = vec![1]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn brute_force_2x2() { - let matrix = arr2(&[ - [3, 2], // - [2, 1], - ]); - let minima = vec![1, 1]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn brute_force_3x3() { - let matrix = arr2(&[ - [3, 4, 4], // - [3, 4, 4], - [2, 3, 3], - ]); - let minima = vec![0, 0, 0]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn brute_force_4x4() { - let matrix = arr2(&[ - [4, 5, 5, 5], // - [2, 3, 3, 3], - [2, 3, 3, 3], - [2, 2, 2, 2], - ]); - let minima = vec![0, 0, 0, 0]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn brute_force_5x5() { - let matrix = arr2(&[ - [3, 2, 4, 5, 6], - [2, 1, 3, 3, 4], - [2, 1, 3, 3, 4], - [3, 2, 4, 3, 4], - [4, 3, 2, 1, 1], - ]); - let minima = vec![1, 1, 1, 1, 3]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } -} diff --git a/third_party/rust/smawk/src/lib.rs b/third_party/rust/smawk/src/lib.rs deleted file mode 100644 index 367d0337dcb9..000000000000 --- a/third_party/rust/smawk/src/lib.rs +++ /dev/null @@ -1,570 +0,0 @@ -//! This crate implements various functions that help speed up dynamic -//! programming, most importantly the SMAWK algorithm for finding row -//! or column minima in a totally monotone matrix with *m* rows and -//! *n* columns in time O(*m* + *n*). This is much better than the -//! brute force solution which would take O(*mn*). When *m* and *n* -//! are of the same order, this turns a quadratic function into a -//! linear function. -//! -//! # Examples -//! -//! Computing the column minima of an *m* ✕ *n* Monge matrix can be -//! done efficiently with `smawk::column_minima`: -//! -//! ``` -//! use smawk::Matrix; -//! -//! let matrix = vec![ -//! vec![3, 2, 4, 5, 6], -//! vec![2, 1, 3, 3, 4], -//! vec![2, 1, 3, 3, 4], -//! vec![3, 2, 4, 3, 4], -//! vec![4, 3, 2, 1, 1], -//! ]; -//! let minima = vec![1, 1, 4, 4, 4]; -//! assert_eq!(smawk::column_minima(&matrix), minima); -//! ``` -//! -//! The `minima` vector gives the index of the minimum value per -//! column, so `minima[0] == 1` since the minimum value in the first -//! column is 2 (row 1). Note that the smallest row index is returned. -//! -//! # Definitions -//! -//! Some of the functions in this crate only work on matrices that are -//! *totally monotone*, which we will define below. -//! -//! ## Monotone Matrices -//! -//! We start with a helper definition. Given an *m* ✕ *n* matrix `M`, -//! we say that `M` is *monotone* when the minimum value of row `i` is -//! found to the left of the minimum value in row `i'` where `i < i'`. -//! -//! More formally, if we let `rm(i)` denote the column index of the -//! left-most minimum value in row `i`, then we have -//! -//! ```text -//! rm(0) ≤ rm(1) ≤ ... ≤ rm(m - 1) -//! ``` -//! -//! This means that as you go down the rows from top to bottom, the -//! row-minima proceed from left to right. -//! -//! The algorithms in this crate deal with finding such row- and -//! column-minima. -//! -//! ## Totally Monotone Matrices -//! -//! We say that a matrix `M` is *totally monotone* when every -//! sub-matrix is monotone. A sub-matrix is formed by the intersection -//! of any two rows `i < i'` and any two columns `j < j'`. -//! -//! This is often expressed as via this equivalent condition: -//! -//! ```text -//! M[i, j] > M[i, j'] => M[i', j] > M[i', j'] -//! ``` -//! -//! for all `i < i'` and `j < j'`. -//! -//! ## Monge Property for Matrices -//! -//! A matrix `M` is said to fulfill the *Monge property* if -//! -//! ```text -//! M[i, j] + M[i', j'] ≤ M[i, j'] + M[i', j] -//! ``` -//! -//! for all `i < i'` and `j < j'`. This says that given any rectangle -//! in the matrix, the sum of the top-left and bottom-right corners is -//! less than or equal to the sum of the bottom-left and upper-right -//! corners. -//! -//! All Monge matrices are totally monotone, so it is enough to -//! establish that the Monge property holds in order to use a matrix -//! with the functions in this crate. If your program is dealing with -//! unknown inputs, it can use [`monge::is_monge`] to verify that a -//! matrix is a Monge matrix. - -#![doc(html_root_url = "https://docs.rs/smawk/0.3.2")] -// The s! macro from ndarray uses unsafe internally, so we can only -// forbid unsafe code when building with the default features. -#![cfg_attr(not(feature = "ndarray"), forbid(unsafe_code))] - -#[cfg(feature = "ndarray")] -pub mod brute_force; -pub mod monge; -#[cfg(feature = "ndarray")] -pub mod recursive; - -/// Minimal matrix trait for two-dimensional arrays. -/// -/// This provides the functionality needed to represent a read-only -/// numeric matrix. You can query the size of the matrix and access -/// elements. Modeled after [`ndarray::Array2`] from the [ndarray -/// crate](https://crates.io/crates/ndarray). -/// -/// Enable the `ndarray` Cargo feature if you want to use it with -/// `ndarray::Array2`. -pub trait Matrix { - /// Return the number of rows. - fn nrows(&self) -> usize; - /// Return the number of columns. - fn ncols(&self) -> usize; - /// Return a matrix element. - fn index(&self, row: usize, column: usize) -> T; -} - -/// Simple and inefficient matrix representation used for doctest -/// examples and simple unit tests. -/// -/// You should prefer implementing it yourself, or you can enable the -/// `ndarray` Cargo feature and use the provided implementation for -/// [`ndarray::Array2`]. -impl Matrix for Vec> { - fn nrows(&self) -> usize { - self.len() - } - fn ncols(&self) -> usize { - self[0].len() - } - fn index(&self, row: usize, column: usize) -> T { - self[row][column] - } -} - -/// Adapting [`ndarray::Array2`] to the `Matrix` trait. -/// -/// **Note: this implementation is only available if you enable the -/// `ndarray` Cargo feature.** -#[cfg(feature = "ndarray")] -impl Matrix for ndarray::Array2 { - #[inline] - fn nrows(&self) -> usize { - self.nrows() - } - #[inline] - fn ncols(&self) -> usize { - self.ncols() - } - #[inline] - fn index(&self, row: usize, column: usize) -> T { - self[[row, column]] - } -} - -/// Compute row minima in O(*m* + *n*) time. -/// -/// This implements the [SMAWK algorithm] for efficiently finding row -/// minima in a totally monotone matrix. -/// -/// The SMAWK algorithm is from Agarwal, Klawe, Moran, Shor, and -/// Wilbur, *Geometric applications of a matrix searching algorithm*, -/// Algorithmica 2, pp. 195-208 (1987) and the code here is a -/// translation [David Eppstein's Python code][pads]. -/// -/// Running time on an *m* ✕ *n* matrix: O(*m* + *n*). -/// -/// # Examples -/// -/// ``` -/// use smawk::Matrix; -/// let matrix = vec![vec![4, 2, 4, 3], -/// vec![5, 3, 5, 3], -/// vec![5, 3, 3, 1]]; -/// assert_eq!(smawk::row_minima(&matrix), -/// vec![1, 1, 3]); -/// ``` -/// -/// # Panics -/// -/// It is an error to call this on a matrix with zero columns. -/// -/// [pads]: https://github.com/jfinkels/PADS/blob/master/pads/smawk.py -/// [SMAWK algorithm]: https://en.wikipedia.org/wiki/SMAWK_algorithm -pub fn row_minima>(matrix: &M) -> Vec { - // Benchmarking shows that SMAWK performs roughly the same on row- - // and column-major matrices. - let mut minima = vec![0; matrix.nrows()]; - smawk_inner( - &|j, i| matrix.index(i, j), - &(0..matrix.ncols()).collect::>(), - &(0..matrix.nrows()).collect::>(), - &mut minima, - ); - minima -} - -#[deprecated(since = "0.3.2", note = "Please use `row_minima` instead.")] -pub fn smawk_row_minima>(matrix: &M) -> Vec { - row_minima(matrix) -} - -/// Compute column minima in O(*m* + *n*) time. -/// -/// This implements the [SMAWK algorithm] for efficiently finding -/// column minima in a totally monotone matrix. -/// -/// The SMAWK algorithm is from Agarwal, Klawe, Moran, Shor, and -/// Wilbur, *Geometric applications of a matrix searching algorithm*, -/// Algorithmica 2, pp. 195-208 (1987) and the code here is a -/// translation [David Eppstein's Python code][pads]. -/// -/// Running time on an *m* ✕ *n* matrix: O(*m* + *n*). -/// -/// # Examples -/// -/// ``` -/// use smawk::Matrix; -/// let matrix = vec![vec![4, 2, 4, 3], -/// vec![5, 3, 5, 3], -/// vec![5, 3, 3, 1]]; -/// assert_eq!(smawk::column_minima(&matrix), -/// vec![0, 0, 2, 2]); -/// ``` -/// -/// # Panics -/// -/// It is an error to call this on a matrix with zero rows. -/// -/// [SMAWK algorithm]: https://en.wikipedia.org/wiki/SMAWK_algorithm -/// [pads]: https://github.com/jfinkels/PADS/blob/master/pads/smawk.py -pub fn column_minima>(matrix: &M) -> Vec { - let mut minima = vec![0; matrix.ncols()]; - smawk_inner( - &|i, j| matrix.index(i, j), - &(0..matrix.nrows()).collect::>(), - &(0..matrix.ncols()).collect::>(), - &mut minima, - ); - minima -} - -#[deprecated(since = "0.3.2", note = "Please use `column_minima` instead.")] -pub fn smawk_column_minima>(matrix: &M) -> Vec { - column_minima(matrix) -} - -/// Compute column minima in the given area of the matrix. The -/// `minima` slice is updated inplace. -fn smawk_inner T>( - matrix: &M, - rows: &[usize], - cols: &[usize], - minima: &mut [usize], -) { - if cols.is_empty() { - return; - } - - let mut stack = Vec::with_capacity(cols.len()); - for r in rows { - // TODO: use stack.last() instead of stack.is_empty() etc - while !stack.is_empty() - && matrix(stack[stack.len() - 1], cols[stack.len() - 1]) - > matrix(*r, cols[stack.len() - 1]) - { - stack.pop(); - } - if stack.len() != cols.len() { - stack.push(*r); - } - } - let rows = &stack; - - let mut odd_cols = Vec::with_capacity(1 + cols.len() / 2); - for (idx, c) in cols.iter().enumerate() { - if idx % 2 == 1 { - odd_cols.push(*c); - } - } - - smawk_inner(matrix, rows, &odd_cols, minima); - - let mut r = 0; - for (c, &col) in cols.iter().enumerate().filter(|(c, _)| c % 2 == 0) { - let mut row = rows[r]; - let last_row = if c == cols.len() - 1 { - rows[rows.len() - 1] - } else { - minima[cols[c + 1]] - }; - let mut pair = (matrix(row, col), row); - while row != last_row { - r += 1; - row = rows[r]; - if (matrix(row, col), row) < pair { - pair = (matrix(row, col), row); - } - } - minima[col] = pair.1; - } -} - -/// Compute upper-right column minima in O(*m* + *n*) time. -/// -/// The input matrix must be totally monotone. -/// -/// The function returns a vector of `(usize, T)`. The `usize` in the -/// tuple at index `j` tells you the row of the minimum value in -/// column `j` and the `T` value is minimum value itself. -/// -/// The algorithm only considers values above the main diagonal, which -/// means that it computes values `v(j)` where: -/// -/// ```text -/// v(0) = initial -/// v(j) = min { M[i, j] | i < j } for j > 0 -/// ``` -/// -/// If we let `r(j)` denote the row index of the minimum value in -/// column `j`, the tuples in the result vector become `(r(j), M[r(j), -/// j])`. -/// -/// The algorithm is an *online* algorithm, in the sense that `matrix` -/// function can refer back to previously computed column minima when -/// determining an entry in the matrix. The guarantee is that we only -/// call `matrix(i, j)` after having computed `v(i)`. This is -/// reflected in the `&[(usize, T)]` argument to `matrix`, which grows -/// as more and more values are computed. -pub fn online_column_minima T>( - initial: T, - size: usize, - matrix: M, -) -> Vec<(usize, T)> { - let mut result = vec![(0, initial)]; - - // State used by the algorithm. - let mut finished = 0; - let mut base = 0; - let mut tentative = 0; - - // Shorthand for evaluating the matrix. We need a macro here since - // we don't want to borrow the result vector. - macro_rules! m { - ($i:expr, $j:expr) => {{ - assert!($i < $j, "(i, j) not above diagonal: ({}, {})", $i, $j); - assert!( - $i < size && $j < size, - "(i, j) out of bounds: ({}, {}), size: {}", - $i, - $j, - size - ); - matrix(&result[..finished + 1], $i, $j) - }}; - } - - // Keep going until we have finished all size columns. Since the - // columns are zero-indexed, we're done when finished == size - 1. - while finished < size - 1 { - // First case: we have already advanced past the previous - // tentative value. We make a new tentative value by applying - // smawk_inner to the largest square submatrix that fits under - // the base. - let i = finished + 1; - if i > tentative { - let rows = (base..finished + 1).collect::>(); - tentative = std::cmp::min(finished + rows.len(), size - 1); - let cols = (finished + 1..tentative + 1).collect::>(); - let mut minima = vec![0; tentative + 1]; - smawk_inner(&|i, j| m![i, j], &rows, &cols, &mut minima); - for col in cols { - let row = minima[col]; - let v = m![row, col]; - if col >= result.len() { - result.push((row, v)); - } else if v < result[col].1 { - result[col] = (row, v); - } - } - finished = i; - continue; - } - - // Second case: the new column minimum is on the diagonal. All - // subsequent ones will be at least as low, so we can clear - // out all our work from higher rows. As in the fourth case, - // the loss of tentative is amortized against the increase in - // base. - let diag = m![i - 1, i]; - if diag < result[i].1 { - result[i] = (i - 1, diag); - base = i - 1; - tentative = i; - finished = i; - continue; - } - - // Third case: row i-1 does not supply a column minimum in any - // column up to tentative. We simply advance finished while - // maintaining the invariant. - if m![i - 1, tentative] >= result[tentative].1 { - finished = i; - continue; - } - - // Fourth and final case: a new column minimum at tentative. - // This allows us to make progress by incorporating rows prior - // to finished into the base. The base invariant holds because - // these rows cannot supply any later column minima. The work - // done when we last advanced tentative (and undone by this - // step) can be amortized against the increase in base. - base = i - 1; - tentative = i; - finished = i; - } - - result -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn smawk_1x1() { - let matrix = vec![vec![2]]; - assert_eq!(row_minima(&matrix), vec![0]); - assert_eq!(column_minima(&matrix), vec![0]); - } - - #[test] - fn smawk_2x1() { - let matrix = vec![ - vec![3], // - vec![2], - ]; - assert_eq!(row_minima(&matrix), vec![0, 0]); - assert_eq!(column_minima(&matrix), vec![1]); - } - - #[test] - fn smawk_1x2() { - let matrix = vec![vec![2, 1]]; - assert_eq!(row_minima(&matrix), vec![1]); - assert_eq!(column_minima(&matrix), vec![0, 0]); - } - - #[test] - fn smawk_2x2() { - let matrix = vec![ - vec![3, 2], // - vec![2, 1], - ]; - assert_eq!(row_minima(&matrix), vec![1, 1]); - assert_eq!(column_minima(&matrix), vec![1, 1]); - } - - #[test] - fn smawk_3x3() { - let matrix = vec![ - vec![3, 4, 4], // - vec![3, 4, 4], - vec![2, 3, 3], - ]; - assert_eq!(row_minima(&matrix), vec![0, 0, 0]); - assert_eq!(column_minima(&matrix), vec![2, 2, 2]); - } - - #[test] - fn smawk_4x4() { - let matrix = vec![ - vec![4, 5, 5, 5], // - vec![2, 3, 3, 3], - vec![2, 3, 3, 3], - vec![2, 2, 2, 2], - ]; - assert_eq!(row_minima(&matrix), vec![0, 0, 0, 0]); - assert_eq!(column_minima(&matrix), vec![1, 3, 3, 3]); - } - - #[test] - fn smawk_5x5() { - let matrix = vec![ - vec![3, 2, 4, 5, 6], - vec![2, 1, 3, 3, 4], - vec![2, 1, 3, 3, 4], - vec![3, 2, 4, 3, 4], - vec![4, 3, 2, 1, 1], - ]; - assert_eq!(row_minima(&matrix), vec![1, 1, 1, 1, 3]); - assert_eq!(column_minima(&matrix), vec![1, 1, 4, 4, 4]); - } - - #[test] - fn online_1x1() { - let matrix = vec![vec![0]]; - let minima = vec![(0, 0)]; - assert_eq!(online_column_minima(0, 1, |_, i, j| matrix[i][j]), minima); - } - - #[test] - fn online_2x2() { - let matrix = vec![ - vec![0, 2], // - vec![0, 0], - ]; - let minima = vec![(0, 0), (0, 2)]; - assert_eq!(online_column_minima(0, 2, |_, i, j| matrix[i][j]), minima); - } - - #[test] - fn online_3x3() { - let matrix = vec![ - vec![0, 4, 4], // - vec![0, 0, 4], - vec![0, 0, 0], - ]; - let minima = vec![(0, 0), (0, 4), (0, 4)]; - assert_eq!(online_column_minima(0, 3, |_, i, j| matrix[i][j]), minima); - } - - #[test] - fn online_4x4() { - let matrix = vec![ - vec![0, 5, 5, 5], // - vec![0, 0, 3, 3], - vec![0, 0, 0, 3], - vec![0, 0, 0, 0], - ]; - let minima = vec![(0, 0), (0, 5), (1, 3), (1, 3)]; - assert_eq!(online_column_minima(0, 4, |_, i, j| matrix[i][j]), minima); - } - - #[test] - fn online_5x5() { - let matrix = vec![ - vec![0, 2, 4, 6, 7], - vec![0, 0, 3, 4, 5], - vec![0, 0, 0, 3, 4], - vec![0, 0, 0, 0, 4], - vec![0, 0, 0, 0, 0], - ]; - let minima = vec![(0, 0), (0, 2), (1, 3), (2, 3), (2, 4)]; - assert_eq!(online_column_minima(0, 5, |_, i, j| matrix[i][j]), minima); - } - - #[test] - fn smawk_works_with_partial_ord() { - let matrix = vec![ - vec![3.0, 2.0], // - vec![2.0, 1.0], - ]; - assert_eq!(row_minima(&matrix), vec![1, 1]); - assert_eq!(column_minima(&matrix), vec![1, 1]); - } - - #[test] - fn online_works_with_partial_ord() { - let matrix = vec![ - vec![0.0, 2.0], // - vec![0.0, 0.0], - ]; - let minima = vec![(0, 0.0), (0, 2.0)]; - assert_eq!( - online_column_minima(0.0, 2, |_, i: usize, j: usize| matrix[i][j]), - minima - ); - } -} diff --git a/third_party/rust/smawk/src/monge.rs b/third_party/rust/smawk/src/monge.rs deleted file mode 100644 index dbc80e15170d..000000000000 --- a/third_party/rust/smawk/src/monge.rs +++ /dev/null @@ -1,121 +0,0 @@ -//! Functions for generating and checking Monge arrays. -//! -//! The functions here are mostly meant to be used for testing -//! correctness of the SMAWK implementation. - -use crate::Matrix; -use std::num::Wrapping; -use std::ops::Add; - -/// Verify that a matrix is a Monge matrix. -/// -/// A [Monge matrix] \(or array) is a matrix where the following -/// inequality holds: -/// -/// ```text -/// M[i, j] + M[i', j'] <= M[i, j'] + M[i', j] for all i < i', j < j' -/// ``` -/// -/// The inequality says that the sum of the main diagonal is less than -/// the sum of the antidiagonal. Checking this condition is done by -/// checking *n* ✕ *m* submatrices, so the running time is O(*mn*). -/// -/// [Monge matrix]: https://en.wikipedia.org/wiki/Monge_array -pub fn is_monge>(matrix: &M) -> bool -where - Wrapping: Add>, -{ - /// Returns `Ok(a + b)` if the computation can be done without - /// overflow, otherwise `Err(a + b - T::MAX - 1)` is returned. - fn checked_add(a: Wrapping, b: Wrapping) -> Result - where - Wrapping: Add>, - { - let sum = a + b; - if sum < a { - Err(sum.0) - } else { - Ok(sum.0) - } - } - - (0..matrix.nrows() - 1) - .flat_map(|row| (0..matrix.ncols() - 1).map(move |col| (row, col))) - .all(|(row, col)| { - let top_left = Wrapping(matrix.index(row, col)); - let top_right = Wrapping(matrix.index(row, col + 1)); - let bot_left = Wrapping(matrix.index(row + 1, col)); - let bot_right = Wrapping(matrix.index(row + 1, col + 1)); - - match ( - checked_add(top_left, bot_right), - checked_add(bot_left, top_right), - ) { - (Ok(a), Ok(b)) => a <= b, // No overflow. - (Err(a), Err(b)) => a <= b, // Double overflow. - (Ok(_), Err(_)) => true, // Anti-diagonal overflow. - (Err(_), Ok(_)) => false, // Main diagonal overflow. - } - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn is_monge_handles_overflow() { - // The x + y <= z + w computations will overflow for an u8 - // matrix unless is_monge is careful. - let matrix: Vec> = vec![ - vec![200, 200, 200, 200], - vec![200, 200, 200, 200], - vec![200, 200, 200, 200], - ]; - assert!(is_monge(&matrix)); - } - - #[test] - fn monge_constant_rows() { - let matrix = vec![ - vec![42, 42, 42, 42], - vec![0, 0, 0, 0], - vec![100, 100, 100, 100], - vec![1000, 1000, 1000, 1000], - ]; - assert!(is_monge(&matrix)); - } - - #[test] - fn monge_constant_cols() { - let matrix = vec![ - vec![42, 0, 100, 1000], - vec![42, 0, 100, 1000], - vec![42, 0, 100, 1000], - vec![42, 0, 100, 1000], - ]; - assert!(is_monge(&matrix)); - } - - #[test] - fn monge_upper_right() { - let matrix = vec![ - vec![10, 10, 42, 42, 42], - vec![10, 10, 42, 42, 42], - vec![10, 10, 10, 10, 10], - vec![10, 10, 10, 10, 10], - ]; - assert!(is_monge(&matrix)); - } - - #[test] - fn monge_lower_left() { - let matrix = vec![ - vec![10, 10, 10, 10, 10], - vec![10, 10, 10, 10, 10], - vec![42, 42, 42, 10, 10], - vec![42, 42, 42, 10, 10], - ]; - assert!(is_monge(&matrix)); - } -} diff --git a/third_party/rust/smawk/src/recursive.rs b/third_party/rust/smawk/src/recursive.rs deleted file mode 100644 index 9df8b9c824d3..000000000000 --- a/third_party/rust/smawk/src/recursive.rs +++ /dev/null @@ -1,191 +0,0 @@ -//! Recursive algorithm for finding column minima. -//! -//! The functions here are mostly meant to be used for testing -//! correctness of the SMAWK implementation. -//! -//! **Note: this module is only available if you enable the `ndarray` -//! Cargo feature.** - -use ndarray::{s, Array2, ArrayView2, Axis}; - -/// Compute row minima in O(*m* + *n* log *m*) time. -/// -/// This function computes row minima in a totally monotone matrix -/// using a recursive algorithm. -/// -/// Running time on an *m* ✕ *n* matrix: O(*m* + *n* log *m*). -/// -/// # Examples -/// -/// ``` -/// let matrix = ndarray::arr2(&[[4, 2, 4, 3], -/// [5, 3, 5, 3], -/// [5, 3, 3, 1]]); -/// assert_eq!(smawk::recursive::row_minima(&matrix), -/// vec![1, 1, 3]); -/// ``` -/// -/// # Panics -/// -/// It is an error to call this on a matrix with zero columns. -pub fn row_minima(matrix: &Array2) -> Vec { - let mut minima = vec![0; matrix.nrows()]; - recursive_inner(matrix.view(), &|| Direction::Row, 0, &mut minima); - minima -} - -/// Compute column minima in O(*n* + *m* log *n*) time. -/// -/// This function computes column minima in a totally monotone matrix -/// using a recursive algorithm. -/// -/// Running time on an *m* ✕ *n* matrix: O(*n* + *m* log *n*). -/// -/// # Examples -/// -/// ``` -/// let matrix = ndarray::arr2(&[[4, 2, 4, 3], -/// [5, 3, 5, 3], -/// [5, 3, 3, 1]]); -/// assert_eq!(smawk::recursive::column_minima(&matrix), -/// vec![0, 0, 2, 2]); -/// ``` -/// -/// # Panics -/// -/// It is an error to call this on a matrix with zero rows. -pub fn column_minima(matrix: &Array2) -> Vec { - let mut minima = vec![0; matrix.ncols()]; - recursive_inner(matrix.view(), &|| Direction::Column, 0, &mut minima); - minima -} - -/// The type of minima (row or column) we compute. -enum Direction { - Row, - Column, -} - -/// Compute the minima along the given direction (`Direction::Row` for -/// row minima and `Direction::Column` for column minima). -/// -/// The direction is given as a generic function argument to allow -/// monomorphization to kick in. The function calls will be inlined -/// and optimized away and the result is that the compiler generates -/// differnet code for finding row and column minima. -fn recursive_inner Direction>( - matrix: ArrayView2<'_, T>, - dir: &F, - offset: usize, - minima: &mut [usize], -) { - if matrix.is_empty() { - return; - } - - let axis = match dir() { - Direction::Row => Axis(0), - Direction::Column => Axis(1), - }; - let mid = matrix.len_of(axis) / 2; - let min_idx = crate::brute_force::lane_minimum(matrix.index_axis(axis, mid)); - minima[mid] = offset + min_idx; - - if mid == 0 { - return; // Matrix has a single row or column, so we're done. - } - - let top_left = match dir() { - Direction::Row => matrix.slice(s![..mid, ..(min_idx + 1)]), - Direction::Column => matrix.slice(s![..(min_idx + 1), ..mid]), - }; - let bot_right = match dir() { - Direction::Row => matrix.slice(s![(mid + 1).., min_idx..]), - Direction::Column => matrix.slice(s![min_idx.., (mid + 1)..]), - }; - recursive_inner(top_left, dir, offset, &mut minima[..mid]); - recursive_inner(bot_right, dir, offset + min_idx, &mut minima[mid + 1..]); -} - -#[cfg(test)] -mod tests { - use super::*; - use ndarray::arr2; - - #[test] - fn recursive_1x1() { - let matrix = arr2(&[[2]]); - let minima = vec![0]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn recursive_2x1() { - let matrix = arr2(&[ - [3], // - [2], - ]); - let minima = vec![0, 0]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn recursive_1x2() { - let matrix = arr2(&[[2, 1]]); - let minima = vec![1]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn recursive_2x2() { - let matrix = arr2(&[ - [3, 2], // - [2, 1], - ]); - let minima = vec![1, 1]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn recursive_3x3() { - let matrix = arr2(&[ - [3, 4, 4], // - [3, 4, 4], - [2, 3, 3], - ]); - let minima = vec![0, 0, 0]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn recursive_4x4() { - let matrix = arr2(&[ - [4, 5, 5, 5], // - [2, 3, 3, 3], - [2, 3, 3, 3], - [2, 2, 2, 2], - ]); - let minima = vec![0, 0, 0, 0]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } - - #[test] - fn recursive_5x5() { - let matrix = arr2(&[ - [3, 2, 4, 5, 6], - [2, 1, 3, 3, 4], - [2, 1, 3, 3, 4], - [3, 2, 4, 3, 4], - [4, 3, 2, 1, 1], - ]); - let minima = vec![1, 1, 1, 1, 3]; - assert_eq!(row_minima(&matrix), minima); - assert_eq!(column_minima(&matrix.reversed_axes()), minima); - } -} diff --git a/third_party/rust/smawk/tests/agreement.rs b/third_party/rust/smawk/tests/agreement.rs deleted file mode 100644 index 2e0343a59a47..000000000000 --- a/third_party/rust/smawk/tests/agreement.rs +++ /dev/null @@ -1,104 +0,0 @@ -#![cfg(feature = "ndarray")] - -use ndarray::{s, Array2}; -use rand::SeedableRng; -use rand_chacha::ChaCha20Rng; -use smawk::{brute_force, online_column_minima, recursive}; - -mod random_monge; -use random_monge::random_monge_matrix; - -/// Check that the brute force, recursive, and SMAWK functions -/// give identical results on a large number of randomly generated -/// Monge matrices. -#[test] -fn column_minima_agree() { - let sizes = vec![1, 2, 3, 4, 5, 10, 15, 20, 30]; - let mut rng = ChaCha20Rng::seed_from_u64(0); - for _ in 0..4 { - for m in sizes.clone().iter() { - for n in sizes.clone().iter() { - let matrix: Array2 = random_monge_matrix(*m, *n, &mut rng); - - // Compute and test row minima. - let brute_force = brute_force::row_minima(&matrix); - let recursive = recursive::row_minima(&matrix); - let smawk = smawk::row_minima(&matrix); - assert_eq!( - brute_force, recursive, - "recursive and brute force differs on:\n{:?}", - matrix - ); - assert_eq!( - brute_force, smawk, - "SMAWK and brute force differs on:\n{:?}", - matrix - ); - - // Do the same for the column minima. - let brute_force = brute_force::column_minima(&matrix); - let recursive = recursive::column_minima(&matrix); - let smawk = smawk::column_minima(&matrix); - assert_eq!( - brute_force, recursive, - "recursive and brute force differs on:\n{:?}", - matrix - ); - assert_eq!( - brute_force, smawk, - "SMAWK and brute force differs on:\n{:?}", - matrix - ); - } - } - } -} - -/// Check that the brute force and online SMAWK functions give -/// identical results on a large number of randomly generated -/// Monge matrices. -#[test] -fn online_agree() { - let sizes = vec![1, 2, 3, 4, 5, 10, 15, 20, 30, 50]; - let mut rng = ChaCha20Rng::seed_from_u64(0); - for _ in 0..5 { - for &size in &sizes { - // Random totally monotone square matrix of the - // desired size. - let mut matrix: Array2 = random_monge_matrix(size, size, &mut rng); - - // Adjust matrix so the column minima are above the - // diagonal. The brute_force::column_minima will still - // work just fine on such a mangled Monge matrix. - let max = *matrix.iter().max().unwrap_or(&0); - for idx in 0..(size as isize) { - // Using the maximum value of the matrix instead - // of i32::max_value() makes for prettier matrices - // in case we want to print them. - matrix.slice_mut(s![idx..idx + 1, ..idx + 1]).fill(max); - } - - // The online algorithm always returns the initial - // value for the left-most column -- without - // inspecting the column at all. So we fill the - // left-most column with this value to have the brute - // force algorithm do the same. - let initial = 42; - matrix.slice_mut(s![0.., ..1]).fill(initial); - - // Brute-force computation of column minima, returned - // in the same form as online_column_minima. - let brute_force = brute_force::column_minima(&matrix) - .iter() - .enumerate() - .map(|(j, &i)| (i, matrix[[i, j]])) - .collect::>(); - let online = online_column_minima(initial, size, |_, i, j| matrix[[i, j]]); - assert_eq!( - brute_force, online, - "brute force and online differ on:\n{:3?}", - matrix - ); - } - } -} diff --git a/third_party/rust/smawk/tests/complexity.rs b/third_party/rust/smawk/tests/complexity.rs deleted file mode 100644 index c9881eaeac49..000000000000 --- a/third_party/rust/smawk/tests/complexity.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![cfg(feature = "ndarray")] - -use ndarray::{Array1, Array2}; -use rand::SeedableRng; -use rand_chacha::ChaCha20Rng; -use smawk::online_column_minima; - -mod random_monge; -use random_monge::random_monge_matrix; - -#[derive(Debug)] -struct LinRegression { - alpha: f64, - beta: f64, - r_squared: f64, -} - -/// Square an expression. Works equally well for floats and matrices. -macro_rules! squared { - ($x:expr) => { - $x * $x - }; -} - -/// Compute the mean of a 1-dimensional array. -macro_rules! mean { - ($a:expr) => { - $a.mean().expect("Mean of empty array") - }; -} - -/// Compute a simple linear regression from the list of values. -/// -/// See . -fn linear_regression(values: &[(usize, i32)]) -> LinRegression { - let xs = values.iter().map(|&(x, _)| x as f64).collect::>(); - let ys = values.iter().map(|&(_, y)| y as f64).collect::>(); - - let xs_mean = mean!(&xs); - let ys_mean = mean!(&ys); - let xs_ys_mean = mean!(&xs * &ys); - - let cov_xs_ys = ((&xs - xs_mean) * (&ys - ys_mean)).sum(); - let var_xs = squared!(&xs - xs_mean).sum(); - - let beta = cov_xs_ys / var_xs; - let alpha = ys_mean - beta * xs_mean; - let r_squared = squared!(xs_ys_mean - xs_mean * ys_mean) - / ((mean!(&xs * &xs) - squared!(xs_mean)) * (mean!(&ys * &ys) - squared!(ys_mean))); - - LinRegression { - alpha: alpha, - beta: beta, - r_squared: r_squared, - } -} - -/// Check that the number of matrix accesses in `online_column_minima` -/// grows as O(*n*) for *n* ✕ *n* matrix. -#[test] -fn online_linear_complexity() { - let mut rng = ChaCha20Rng::seed_from_u64(0); - let mut data = vec![]; - - for &size in &[1, 2, 3, 4, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100] { - let matrix: Array2 = random_monge_matrix(size, size, &mut rng); - let count = std::cell::RefCell::new(0); - online_column_minima(0, size, |_, i, j| { - *count.borrow_mut() += 1; - matrix[[i, j]] - }); - data.push((size, count.into_inner())); - } - - let lin_reg = linear_regression(&data); - assert!( - lin_reg.r_squared > 0.95, - "r² = {:.4} is lower than expected for a linear fit\nData points: {:?}\n{:?}", - lin_reg.r_squared, - data, - lin_reg - ); -} diff --git a/third_party/rust/smawk/tests/monge.rs b/third_party/rust/smawk/tests/monge.rs deleted file mode 100644 index 67058a75a504..000000000000 --- a/third_party/rust/smawk/tests/monge.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![cfg(feature = "ndarray")] - -use ndarray::{arr2, Array, Array2}; -use rand::SeedableRng; -use rand_chacha::ChaCha20Rng; -use smawk::monge::is_monge; - -mod random_monge; -use random_monge::{random_monge_matrix, MongePrim}; - -#[test] -fn random_monge() { - let mut rng = ChaCha20Rng::seed_from_u64(0); - let matrix: Array2 = random_monge_matrix(5, 5, &mut rng); - - assert!(is_monge(&matrix)); - assert_eq!( - matrix, - arr2(&[ - [2, 3, 4, 4, 5], - [5, 5, 6, 6, 7], - [3, 3, 4, 4, 5], - [5, 2, 3, 3, 4], - [5, 2, 3, 3, 4] - ]) - ); -} - -#[test] -fn monge_constant_rows() { - let mut rng = ChaCha20Rng::seed_from_u64(0); - let matrix: Array2 = MongePrim::ConstantRows.to_matrix(5, 4, &mut rng); - assert!(is_monge(&matrix)); - for row in matrix.rows() { - let elem = row[0]; - assert_eq!(row, Array::from_elem(matrix.ncols(), elem)); - } -} - -#[test] -fn monge_constant_cols() { - let mut rng = ChaCha20Rng::seed_from_u64(0); - let matrix: Array2 = MongePrim::ConstantCols.to_matrix(5, 4, &mut rng); - assert!(is_monge(&matrix)); - for column in matrix.columns() { - let elem = column[0]; - assert_eq!(column, Array::from_elem(matrix.nrows(), elem)); - } -} - -#[test] -fn monge_upper_right_ones() { - let mut rng = ChaCha20Rng::seed_from_u64(1); - let matrix: Array2 = MongePrim::UpperRightOnes.to_matrix(5, 4, &mut rng); - assert!(is_monge(&matrix)); - assert_eq!( - matrix, - arr2(&[ - [0, 0, 1, 1], - [0, 0, 1, 1], - [0, 0, 1, 1], - [0, 0, 0, 0], - [0, 0, 0, 0] - ]) - ); -} - -#[test] -fn monge_lower_left_ones() { - let mut rng = ChaCha20Rng::seed_from_u64(1); - let matrix: Array2 = MongePrim::LowerLeftOnes.to_matrix(5, 4, &mut rng); - assert!(is_monge(&matrix)); - assert_eq!( - matrix, - arr2(&[ - [0, 0, 0, 0], - [0, 0, 0, 0], - [1, 1, 0, 0], - [1, 1, 0, 0], - [1, 1, 0, 0] - ]) - ); -} diff --git a/third_party/rust/smawk/tests/random_monge/mod.rs b/third_party/rust/smawk/tests/random_monge/mod.rs deleted file mode 100644 index 50a932fbeb2e..000000000000 --- a/third_party/rust/smawk/tests/random_monge/mod.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Test functionality for generating random Monge matrices. - -// The code is put here so we can reuse it in different integration -// tests, without Cargo finding it when `cargo test` is run. See the -// section on "Submodules in Integration Tests" in -// https://doc.rust-lang.org/book/ch11-03-test-organization.html - -use ndarray::{s, Array2}; -use num_traits::PrimInt; -use rand::distributions::{Distribution, Standard}; -use rand::Rng; - -/// A Monge matrix can be decomposed into one of these primitive -/// building blocks. -#[derive(Copy, Clone)] -pub enum MongePrim { - ConstantRows, - ConstantCols, - UpperRightOnes, - LowerLeftOnes, -} - -impl MongePrim { - /// Generate a Monge matrix from a primitive. - pub fn to_matrix(&self, m: usize, n: usize, rng: &mut R) -> Array2 - where - Standard: Distribution, - { - let mut matrix = Array2::from_elem((m, n), T::zero()); - // Avoid panic in UpperRightOnes and LowerLeftOnes below. - if m == 0 || n == 0 { - return matrix; - } - - match *self { - MongePrim::ConstantRows => { - for mut row in matrix.rows_mut() { - if rng.gen::() { - row.fill(T::one()) - } - } - } - MongePrim::ConstantCols => { - for mut col in matrix.columns_mut() { - if rng.gen::() { - col.fill(T::one()) - } - } - } - MongePrim::UpperRightOnes => { - let i = rng.gen_range(0..(m + 1) as isize); - let j = rng.gen_range(0..(n + 1) as isize); - matrix.slice_mut(s![..i, -j..]).fill(T::one()); - } - MongePrim::LowerLeftOnes => { - let i = rng.gen_range(0..(m + 1) as isize); - let j = rng.gen_range(0..(n + 1) as isize); - matrix.slice_mut(s![-i.., ..j]).fill(T::one()); - } - } - - matrix - } -} - -/// Generate a random Monge matrix. -pub fn random_monge_matrix(m: usize, n: usize, rng: &mut R) -> Array2 -where - Standard: Distribution, -{ - let monge_primitives = [ - MongePrim::ConstantRows, - MongePrim::ConstantCols, - MongePrim::LowerLeftOnes, - MongePrim::UpperRightOnes, - ]; - let mut matrix = Array2::from_elem((m, n), T::zero()); - for _ in 0..(m + n) { - let monge = monge_primitives[rng.gen_range(0..monge_primitives.len())]; - matrix = matrix + monge.to_matrix(m, n, rng); - } - matrix -} diff --git a/third_party/rust/smawk/tests/version-numbers.rs b/third_party/rust/smawk/tests/version-numbers.rs deleted file mode 100644 index 288592d02f1f..000000000000 --- a/third_party/rust/smawk/tests/version-numbers.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[test] -fn test_readme_deps() { - version_sync::assert_markdown_deps_updated!("README.md"); -} - -#[test] -fn test_html_root_url() { - version_sync::assert_html_root_url_updated!("src/lib.rs"); -} diff --git a/third_party/rust/suggest/.cargo-checksum.json b/third_party/rust/suggest/.cargo-checksum.json dissimilarity index 100% index 120a503f297e..4bb3d097c5aa 100644 --- a/third_party/rust/suggest/.cargo-checksum.json +++ b/third_party/rust/suggest/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"05e4d7f7b3649a3e3fa441c4af53a633d18f20bb04fd761ed33fc9d461fd0dee","README.md":"fb72d0028586cab1421b853ef529d7ce78ad7316818b7733a4f3488b0fba67f7","benches/benchmark_all.rs":"c2343c9197b6d9ccb0798d7701b1b0d2569d494dd31a975d21d7ec6f26e32879","build.rs":"78780c5cccfe22c3ff4198624b9e188559c437c3e6fa1c8bb66548eee6aa66bf","src/benchmarks/README.md":"ee6d50df2c31cfd80a5bc047011b518dcf57f1ef928a811bb770f1a09f41b3de","src/benchmarks/client.rs":"5d5db3f6e132654c06532feba15f98576122f6b9572ab5fa27b0c67d5b39ecb6","src/benchmarks/ingest.rs":"1ffdc403fb945ea0b58353df9773ba45ab0e9082d61dd5330ad49fad8cbb5d9f","src/benchmarks/mod.rs":"fe1898ba4d783213525da10d92858ee84cebfd22749bad7aeb461d338fe5504a","src/bin/debug_ingestion_sizes.rs":"ce6e810be7b3fc19e826d75b622b82cfab5a1a99397a6d0833c2c4eebff2d364","src/config.rs":"206ae9dc768c755649cb0c88a7b1fc3c926c715441784f61e9dc06a8a02fc568","src/db.rs":"734f5fd9f36f03c07a508a9a353872b81107f5fe09f27294ba27d7e1249e3988","src/error.rs":"f563210a6c050d98ec85e0f6d9401e7373bfb816e865e8edabbabb23d848ba13","src/keyword.rs":"988d0ab021c0df19cfd3c519df7d37f606bf984cd14d0efca4e5a7aff88344dd","src/lib.rs":"91ebbe0e1ffb99eefde204f81bc6bb199b4941976347baf1f132fd0ede20479c","src/pocket.rs":"1316668840ec9b4ea886223921dc9d3b5a1731d1a5206c0b1089f2a6c45c1b7b","src/provider.rs":"fe76f19a223f5cac056c7d48525087ca2c26bf0629b0e11b1f8dc98d165c8bb2","src/rs.rs":"e3eabde58c859ebe1154bf8da56ca134ace135934e3f280acc8186b4204399b3","src/schema.rs":"8b21006940e872658d722b52ba171280c96789eecf614b837d8cdbc9153ab576","src/store.rs":"413779074db3ce4589c31cd4fb0a050d44d1cbad1df3c94101d03e98efdf09cb","src/suggest.udl":"de50ea5c7ece0ae0ff4798979e0e12a5227b42bf024d48b6f585ea30a5133eb3","src/suggestion.rs":"f31227779d13d1b03a622e08a417ceba4afb161885a01c2bc87a6a652b5e8be5","src/yelp.rs":"9c0dc02a994cc05df524aa4ef337d10f575d1891259193b6419fed6fe279cb54","uniffi.toml":"f26317442ddb5b3281245bef6e60ffcb78bb95d29fe4a351a56dbb88d4ec8aab"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"4aa81cff67e67b08ba3348c1acddaa5aee887df3c35006754c9cda4273a94458","README.md":"fb72d0028586cab1421b853ef529d7ce78ad7316818b7733a4f3488b0fba67f7","build.rs":"78780c5cccfe22c3ff4198624b9e188559c437c3e6fa1c8bb66548eee6aa66bf","src/config.rs":"206ae9dc768c755649cb0c88a7b1fc3c926c715441784f61e9dc06a8a02fc568","src/db.rs":"b88f2162d4d43efa52b254b6c1e766dbf9715c40d47f94b321d7b2bbba69d39e","src/error.rs":"f563210a6c050d98ec85e0f6d9401e7373bfb816e865e8edabbabb23d848ba13","src/keyword.rs":"988d0ab021c0df19cfd3c519df7d37f606bf984cd14d0efca4e5a7aff88344dd","src/lib.rs":"65a035dbfb17e2d2d9f237ad52dc03982ae28c70e3dcf3d96cc9f2d7af79efe3","src/pocket.rs":"1316668840ec9b4ea886223921dc9d3b5a1731d1a5206c0b1089f2a6c45c1b7b","src/provider.rs":"fe76f19a223f5cac056c7d48525087ca2c26bf0629b0e11b1f8dc98d165c8bb2","src/rs.rs":"7f9136b5cc6f5617a391e0abd5637f9cc63c50fb206f787fd7b92f39b7bbfb5d","src/schema.rs":"d9aba13d9e299819eda88ba3cba6971ec54f555c37ab7589689891531e1390c8","src/store.rs":"8505c51320aea5cb292df8cf8bc4f096e67a3603860f8575e681e630212a0248","src/suggest.udl":"288cef097b74426128b900dcf2d74f09868b88831f0cec4ecefbb5f9e8acf01f","src/suggestion.rs":"477736d6bc3e25c0fccf3e2e69e12882a10db1c57455ee7dca149443b59e0c3b","src/yelp.rs":"9c0dc02a994cc05df524aa4ef337d10f575d1891259193b6419fed6fe279cb54","uniffi.toml":"f26317442ddb5b3281245bef6e60ffcb78bb95d29fe4a351a56dbb88d4ec8aab"},"package":null} \ No newline at end of file diff --git a/third_party/rust/suggest/Cargo.toml b/third_party/rust/suggest/Cargo.toml index cec02ceadf49..17ce1af26d08 100644 --- a/third_party/rust/suggest/Cargo.toml +++ b/third_party/rust/suggest/Cargo.toml @@ -21,15 +21,6 @@ description = "Manages sponsored and web suggestions for Firefox Suggest" readme = "README.md" license = "MPL-2.0" -[[bin]] -name = "debug_ingestion_sizes" -required-features = ["benchmark_api"] - -[[bench]] -name = "benchmark_all" -harness = false -required-features = ["benchmark_api"] - [dependencies] anyhow = "1.0" chrono = "0.4" @@ -37,7 +28,7 @@ once_cell = "1.5" parking_lot = ">=0.11,<=0.12" serde_json = "1" thiserror = "1" -uniffi = "0.27.1" +uniffi = "0.25.2" [dependencies.error-support] path = "../support/error" @@ -62,10 +53,6 @@ features = ["derive"] [dependencies.sql-support] path = "../support/sql" -[dependencies.tempfile] -version = "3.2.0" -optional = true - [dependencies.url] version = "2.1" features = ["serde"] @@ -73,12 +60,7 @@ features = ["serde"] [dependencies.viaduct] path = "../viaduct" -[dependencies.viaduct-reqwest] -path = "../support/viaduct-reqwest" -optional = true - [dev-dependencies] -criterion = "0.5" expect-test = "1.4" hex = "0.4" @@ -90,11 +72,5 @@ default-features = false path = "../support/rc_crypto" [build-dependencies.uniffi] -version = "0.27.1" +version = "0.25.2" features = ["build"] - -[features] -benchmark_api = [ - "tempfile", - "viaduct-reqwest", -] diff --git a/third_party/rust/suggest/benches/benchmark_all.rs b/third_party/rust/suggest/benches/benchmark_all.rs deleted file mode 100644 index 2e328e58040a..000000000000 --- a/third_party/rust/suggest/benches/benchmark_all.rs +++ /dev/null @@ -1,25 +0,0 @@ -use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; -use suggest::benchmarks::{ingest, BenchmarkWithInput}; - -pub fn ingest_single_provider(c: &mut Criterion) { - let mut group = c.benchmark_group("ingest"); - viaduct_reqwest::use_reqwest_backend(); - // This needs to be 10 for now, or else the `ingest-amp-wikipedia` benchmark would take around - // 100s to run which feels like too long. `ingest-amp-mobile` also would take a around 50s. - group.sample_size(10); - for (name, benchmark) in ingest::all_benchmarks() { - group.bench_function(format!("ingest-{name}"), |b| { - b.iter_batched( - || benchmark.generate_input(), - |input| benchmark.benchmarked_code(input), - // See https://docs.rs/criterion/latest/criterion/enum.BatchSize.html#variants for - // a discussion of this. PerIteration is chosen for these benchmarks because the - // input holds a database file handle - BatchSize::PerIteration, - ); - }); - } -} - -criterion_group!(benches, ingest_single_provider); -criterion_main!(benches); diff --git a/third_party/rust/suggest/src/benchmarks/README.md b/third_party/rust/suggest/src/benchmarks/README.md deleted file mode 100644 index 45150d8413a9..000000000000 --- a/third_party/rust/suggest/src/benchmarks/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Suggest benchmarking code - -Use `cargo suggest-bench` to run these benchmarks. - -The main benchmarking code lives here, while the criterion integration code lives in the `benches/` -directory. - -## Benchmarks - -### ingest-[provider-type] - -Time it takes to ingest all suggestions for a provider type on an empty database. -The bechmark downloads network resources in advance in order to exclude the network request time -from these measurements. - -### Benchmarks it would be nice to have - -- Ingestion with synthetic data. This would isolate the benchmark from changes to the RS database. -- Fetching suggestions - -## cargo suggest-debug-ingestion-sizes - -Run this to get row counts for all database tables. This can be very useful for improving -benchmarks, since targeting the tables with the largest number of rows will usually lead to the -largest improvements. - -The command also prints out the size of all remote-settings attachments, which can be good to -optimize on its own since it represents the amount of data user's need to download. diff --git a/third_party/rust/suggest/src/benchmarks/client.rs b/third_party/rust/suggest/src/benchmarks/client.rs deleted file mode 100644 index f5a21fd9cc1a..000000000000 --- a/third_party/rust/suggest/src/benchmarks/client.rs +++ /dev/null @@ -1,97 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use crate::{rs::SuggestRemoteSettingsClient, Result}; -use parking_lot::Mutex; -use remote_settings::{Client, GetItemsOptions, RemoteSettingsConfig, RemoteSettingsResponse}; -use std::collections::HashMap; - -/// Remotes settings client that runs during the benchmark warm-up phase. -/// -/// This should be used to run a full ingestion. -/// Then it can be converted into a [RemoteSettingsBenchmarkClient], which allows benchmark code to exclude the network request time. -/// [RemoteSettingsBenchmarkClient] implements [SuggestRemoteSettingsClient] by getting data from a HashMap rather than hitting the network. -pub struct RemoteSettingsWarmUpClient { - client: Client, - pub get_records_responses: Mutex>, - pub get_attachment_responses: Mutex>>, -} - -impl RemoteSettingsWarmUpClient { - pub fn new() -> Self { - Self { - client: Client::new(RemoteSettingsConfig { - server_url: None, - bucket_name: None, - collection_name: crate::rs::REMOTE_SETTINGS_COLLECTION.into(), - }) - .unwrap(), - get_records_responses: Mutex::new(HashMap::new()), - get_attachment_responses: Mutex::new(HashMap::new()), - } - } -} - -impl Default for RemoteSettingsWarmUpClient { - fn default() -> Self { - Self::new() - } -} - -impl SuggestRemoteSettingsClient for RemoteSettingsWarmUpClient { - fn get_records_with_options( - &self, - options: &GetItemsOptions, - ) -> Result { - let response = self.client.get_records_with_options(options)?; - self.get_records_responses - .lock() - .insert(options.clone(), response.clone()); - Ok(response) - } - - fn get_attachment(&self, location: &str) -> Result> { - let response = self.client.get_attachment(location)?; - self.get_attachment_responses - .lock() - .insert(location.to_string(), response.clone()); - Ok(response) - } -} - -#[derive(Clone)] -pub struct RemoteSettingsBenchmarkClient { - pub get_records_responses: HashMap, - pub get_attachment_responses: HashMap>, -} - -impl SuggestRemoteSettingsClient for RemoteSettingsBenchmarkClient { - fn get_records_with_options( - &self, - options: &GetItemsOptions, - ) -> Result { - Ok(self - .get_records_responses - .get(options) - .unwrap_or_else(|| panic!("options not found: {options:?}")) - .clone()) - } - - fn get_attachment(&self, location: &str) -> Result> { - Ok(self - .get_attachment_responses - .get(location) - .unwrap_or_else(|| panic!("location not found: {location:?}")) - .clone()) - } -} - -impl From for RemoteSettingsBenchmarkClient { - fn from(warm_up_client: RemoteSettingsWarmUpClient) -> Self { - Self { - get_records_responses: warm_up_client.get_records_responses.into_inner(), - get_attachment_responses: warm_up_client.get_attachment_responses.into_inner(), - } - } -} diff --git a/third_party/rust/suggest/src/benchmarks/ingest.rs b/third_party/rust/suggest/src/benchmarks/ingest.rs deleted file mode 100644 index bbefc6a00a86..000000000000 --- a/third_party/rust/suggest/src/benchmarks/ingest.rs +++ /dev/null @@ -1,116 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use crate::{ - benchmarks::{ - client::{RemoteSettingsBenchmarkClient, RemoteSettingsWarmUpClient}, - BenchmarkWithInput, - }, - rs::SuggestRecordType, - store::SuggestStoreInner, - SuggestIngestionConstraints, -}; -use std::sync::atomic::{AtomicU32, Ordering}; - -static DB_FILE_COUNTER: AtomicU32 = AtomicU32::new(0); - -pub struct IngestBenchmark { - temp_dir: tempfile::TempDir, - client: RemoteSettingsBenchmarkClient, - record_type: SuggestRecordType, -} - -impl IngestBenchmark { - pub fn new(record_type: SuggestRecordType) -> Self { - let temp_dir = tempfile::tempdir().unwrap(); - let store = SuggestStoreInner::new( - temp_dir.path().join("warmup.sqlite"), - RemoteSettingsWarmUpClient::new(), - ); - store.benchmark_ingest_records_by_type(record_type); - Self { - client: RemoteSettingsBenchmarkClient::from(store.into_settings_client()), - temp_dir, - record_type, - } - } -} - -// The input for each benchmark is `SuggestStoreInner` with a fresh database. -// -// This is wrapped in a newtype so that it can be exposed in the public trait -pub struct InputType(SuggestStoreInner); - -impl BenchmarkWithInput for IngestBenchmark { - type Input = InputType; - - fn generate_input(&self) -> Self::Input { - let data_path = self.temp_dir.path().join(format!( - "db{}.sqlite", - DB_FILE_COUNTER.fetch_add(1, Ordering::Relaxed) - )); - let store = SuggestStoreInner::new(data_path, self.client.clone()); - store.ensure_db_initialized(); - InputType(store) - } - - fn benchmarked_code(&self, input: Self::Input) { - let InputType(store) = input; - store.benchmark_ingest_records_by_type(self.record_type); - } -} - -/// Get IngestBenchmark instances for all record types -pub fn all_benchmarks() -> Vec<(&'static str, IngestBenchmark)> { - vec![ - ("icon", IngestBenchmark::new(SuggestRecordType::Icon)), - ( - "amp-wikipedia", - IngestBenchmark::new(SuggestRecordType::AmpWikipedia), - ), - ("amo", IngestBenchmark::new(SuggestRecordType::Amo)), - ("pocket", IngestBenchmark::new(SuggestRecordType::Pocket)), - ("yelp", IngestBenchmark::new(SuggestRecordType::Yelp)), - ("mdn", IngestBenchmark::new(SuggestRecordType::Mdn)), - ("weather", IngestBenchmark::new(SuggestRecordType::Weather)), - ( - "global-config", - IngestBenchmark::new(SuggestRecordType::GlobalConfig), - ), - ( - "amp-mobile", - IngestBenchmark::new(SuggestRecordType::AmpMobile), - ), - ] -} - -pub fn print_debug_ingestion_sizes() { - viaduct_reqwest::use_reqwest_backend(); - let store = SuggestStoreInner::new( - "file:debug_ingestion_sizes?mode=memory&cache=shared", - RemoteSettingsWarmUpClient::new(), - ); - store - .ingest(SuggestIngestionConstraints::default()) - .unwrap(); - let table_row_counts = store.table_row_counts(); - let client = store.into_settings_client(); - let total_attachment_size: usize = client - .get_attachment_responses - .lock() - .values() - .map(|data| data.len()) - .sum(); - - println!( - "Total attachment size: {}kb", - (total_attachment_size + 500) / 1000 - ); - println!(); - println!("Database table row counts"); - println!("-------------------------"); - for (name, count) in table_row_counts { - println!("{name:30}: {count}"); - } -} diff --git a/third_party/rust/suggest/src/benchmarks/mod.rs b/third_party/rust/suggest/src/benchmarks/mod.rs deleted file mode 100644 index eb3b2e8abe59..000000000000 --- a/third_party/rust/suggest/src/benchmarks/mod.rs +++ /dev/null @@ -1,40 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//! Benchmarking support -//! -//! Benchmarks are split up into two parts: the functions to be benchmarked live here, which the benchmarking code itself lives in `benches/bench.rs`. -//! It's easier to write benchmarking code inside the main crate, where we have access to private items. -//! However, it's easier to integrate with Cargo and criterion if benchmarks live in a separate crate. -//! -//! All benchmarks are defined as structs that implement either the [Benchmark] or [BenchmarkWithInput] - -pub mod client; -pub mod ingest; - -/// Trait for simple benchmarks -/// -/// This supports simple benchmarks that don't require any input. Note: global setup can be done -/// in the `new()` method for the struct. -pub trait Benchmark { - /// Perform the operations that we're benchmarking. - fn benchmarked_code(&self); -} - -/// Trait for benchmarks that require input -/// -/// This will run using Criterion's `iter_batched` function. Criterion will create a batch of -/// inputs, then pass each one to benchmark. -/// -/// This supports simple benchmarks that don't require any input. Note: global setup can be done -/// in the `new()` method for the struct. -pub trait BenchmarkWithInput { - type Input; - - /// Generate the input (this is not included in the benchmark time) - fn generate_input(&self) -> Self::Input; - - /// Perform the operations that we're benchmarking. - fn benchmarked_code(&self, input: Self::Input); -} diff --git a/third_party/rust/suggest/src/bin/debug_ingestion_sizes.rs b/third_party/rust/suggest/src/bin/debug_ingestion_sizes.rs deleted file mode 100644 index 14ca3d9462b9..000000000000 --- a/third_party/rust/suggest/src/bin/debug_ingestion_sizes.rs +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use suggest::benchmarks::ingest; - -fn main() { - ingest::print_debug_ingestion_sizes() -} diff --git a/third_party/rust/suggest/src/db.rs b/third_party/rust/suggest/src/db.rs index 0412c50d8fac..426b1bf09882 100644 --- a/third_party/rust/suggest/src/db.rs +++ b/third_party/rust/suggest/src/db.rs @@ -23,7 +23,7 @@ use crate::{ rs::{ DownloadedAmoSuggestion, DownloadedAmpSuggestion, DownloadedAmpWikipediaSuggestion, DownloadedMdnSuggestion, DownloadedPocketSuggestion, DownloadedWeatherData, - DownloadedWikipediaSuggestion, SuggestRecordId, + SuggestRecordId, }, schema::{clear_database, SuggestConnectionInitializer, VERSION}, store::{UnparsableRecord, UnparsableRecords}, @@ -252,7 +252,6 @@ impl<'a> SuggestDao<'a> { WHERE s.provider = :provider AND k.keyword = :keyword - AND NOT EXISTS (SELECT 1 FROM dismissed_suggestions WHERE url=s.url) "#, named_params! { ":keyword": keyword_lowercased, @@ -349,7 +348,6 @@ impl<'a> SuggestDao<'a> { WHERE s.provider = :provider AND k.keyword = :keyword - AND NOT EXISTS (SELECT 1 FROM dismissed_suggestions WHERE url=s.url) "#, named_params! { ":keyword": keyword_lowercased, @@ -432,7 +430,6 @@ impl<'a> SuggestDao<'a> { k.keyword_prefix = :keyword_prefix AND (k.keyword_suffix BETWEEN :keyword_suffix AND :keyword_suffix || x'FFFF') AND s.provider = :provider - AND NOT EXISTS (SELECT 1 FROM dismissed_suggestions WHERE url=s.url) GROUP BY s.id ORDER BY @@ -532,7 +529,6 @@ impl<'a> SuggestDao<'a> { k.keyword_prefix = :keyword_prefix AND (k.keyword_suffix BETWEEN :keyword_suffix AND :keyword_suffix || x'FFFF') AND s.provider = :provider - AND NOT EXISTS (SELECT 1 FROM dismissed_suggestions WHERE url=s.url) GROUP BY s.id, k.confidence @@ -670,15 +666,35 @@ impl<'a> SuggestDao<'a> { record_id: &SuggestRecordId, suggestions: &[DownloadedAmoSuggestion], ) -> Result<()> { - let mut suggestion_insert = SuggestionInsertStatement::new(self.conn)?; for suggestion in suggestions { self.scope.err_if_interrupted()?; - let suggestion_id = suggestion_insert.execute( - record_id, - &suggestion.title, - &suggestion.url, - suggestion.score, - SuggestionProvider::Amo, + let suggestion_id: i64 = self.conn.query_row_and_then_cachable( + &format!( + "INSERT INTO suggestions( + record_id, + provider, + title, + url, + score + ) + VALUES( + :record_id, + {}, + :title, + :url, + :score + ) + RETURNING id", + SuggestionProvider::Amo as u8 + ), + named_params! { + ":record_id": record_id.as_str(), + ":title": suggestion.title, + ":url": suggestion.url, + ":score": suggestion.score, + }, + |row| row.get(0), + true, )?; self.conn.execute( "INSERT INTO amo_custom_details( @@ -740,30 +756,86 @@ impl<'a> SuggestDao<'a> { record_id: &SuggestRecordId, suggestions: &[DownloadedAmpWikipediaSuggestion], ) -> Result<()> { - // Prepare statements outside of the loop. This results in a large performance - // improvement on a fresh ingest, since there are so many rows. - let mut suggestion_insert = SuggestionInsertStatement::new(self.conn)?; - let mut amp_insert = AmpInsertStatement::new(self.conn)?; - let mut wiki_insert = WikipediaInsertStatement::new(self.conn)?; - let mut keyword_insert = KeywordInsertStatement::new(self.conn)?; for suggestion in suggestions { self.scope.err_if_interrupted()?; let common_details = suggestion.common_details(); let provider = suggestion.provider(); - let suggestion_id = suggestion_insert.execute( - record_id, - &common_details.title, - &common_details.url, - common_details.score.unwrap_or(DEFAULT_SUGGESTION_SCORE), - provider, + let suggestion_id: i64 = self.conn.query_row_and_then_cachable( + &format!( + "INSERT INTO suggestions( + record_id, + provider, + title, + url, + score + ) + VALUES( + :record_id, + {}, + :title, + :url, + :score + ) + RETURNING id", + provider as u8 + ), + named_params! { + ":record_id": record_id.as_str(), + ":title": common_details.title, + ":url": common_details.url, + ":score": common_details.score.unwrap_or(DEFAULT_SUGGESTION_SCORE) + }, + |row| row.get(0), + true, )?; match suggestion { DownloadedAmpWikipediaSuggestion::Amp(amp) => { - amp_insert.execute(suggestion_id, amp)?; + self.conn.execute( + "INSERT INTO amp_custom_details( + suggestion_id, + advertiser, + block_id, + iab_category, + impression_url, + click_url, + icon_id + ) + VALUES( + :suggestion_id, + :advertiser, + :block_id, + :iab_category, + :impression_url, + :click_url, + :icon_id + )", + named_params! { + ":suggestion_id": suggestion_id, + ":advertiser": amp.advertiser, + ":block_id": amp.block_id, + ":iab_category": amp.iab_category, + ":impression_url": amp.impression_url, + ":click_url": amp.click_url, + ":icon_id": amp.icon_id, + }, + )?; } DownloadedAmpWikipediaSuggestion::Wikipedia(wikipedia) => { - wiki_insert.execute(suggestion_id, wikipedia)?; + self.conn.execute( + "INSERT INTO wikipedia_custom_details( + suggestion_id, + icon_id + ) + VALUES( + :suggestion_id, + :icon_id + )", + named_params! { + ":suggestion_id": suggestion_id, + ":icon_id": wikipedia.icon_id, + }, + )?; } } let mut full_keyword_inserter = FullKeywordInserter::new(self.conn, suggestion_id); @@ -777,11 +849,25 @@ impl<'a> SuggestDao<'a> { _ => None, }; - keyword_insert.execute( - suggestion_id, - keyword.keyword, - full_keyword_id, - keyword.rank, + self.conn.execute( + "INSERT INTO keywords( + keyword, + suggestion_id, + full_keyword_id, + rank + ) + VALUES( + :keyword, + :suggestion_id, + :full_keyword_id, + :rank + )", + named_params! { + ":keyword": keyword.keyword, + ":rank": keyword.rank, + ":suggestion_id": suggestion_id, + ":full_keyword_id": full_keyword_id, + }, )?; } } @@ -795,20 +881,66 @@ impl<'a> SuggestDao<'a> { record_id: &SuggestRecordId, suggestions: &[DownloadedAmpSuggestion], ) -> Result<()> { - let mut suggestion_insert = SuggestionInsertStatement::new(self.conn)?; - let mut amp_insert = AmpInsertStatement::new(self.conn)?; - let mut keyword_insert = KeywordInsertStatement::new(self.conn)?; for suggestion in suggestions { self.scope.err_if_interrupted()?; let common_details = &suggestion.common_details; - let suggestion_id = suggestion_insert.execute( - record_id, - &common_details.title, - &common_details.url, - common_details.score.unwrap_or(DEFAULT_SUGGESTION_SCORE), - SuggestionProvider::AmpMobile, + let suggestion_id: i64 = self.conn.query_row_and_then_cachable( + &format!( + "INSERT INTO suggestions( + record_id, + provider, + title, + url, + score + ) + VALUES( + :record_id, + {}, + :title, + :url, + :score + ) + RETURNING id", + SuggestionProvider::AmpMobile as u8 + ), + named_params! { + ":record_id": record_id.as_str(), + ":title": common_details.title, + ":url": common_details.url, + ":score": common_details.score.unwrap_or(DEFAULT_SUGGESTION_SCORE) + }, + |row| row.get(0), + true, + )?; + self.conn.execute( + "INSERT INTO amp_custom_details( + suggestion_id, + advertiser, + block_id, + iab_category, + impression_url, + click_url, + icon_id + ) + VALUES( + :suggestion_id, + :advertiser, + :block_id, + :iab_category, + :impression_url, + :click_url, + :icon_id + )", + named_params! { + ":suggestion_id": suggestion_id, + ":advertiser": suggestion.advertiser, + ":block_id": suggestion.block_id, + ":iab_category": suggestion.iab_category, + ":impression_url": suggestion.impression_url, + ":click_url": suggestion.click_url, + ":icon_id": suggestion.icon_id, + }, )?; - amp_insert.execute(suggestion_id, suggestion)?; let mut full_keyword_inserter = FullKeywordInserter::new(self.conn, suggestion_id); for keyword in common_details.keywords() { @@ -816,11 +948,25 @@ impl<'a> SuggestDao<'a> { .full_keyword .map(|full_keyword| full_keyword_inserter.maybe_insert(full_keyword)) .transpose()?; - keyword_insert.execute( - suggestion_id, - keyword.keyword, - full_keyword_id, - keyword.rank, + self.conn.execute( + "INSERT INTO keywords( + keyword, + suggestion_id, + full_keyword_id, + rank + ) + VALUES( + :keyword, + :suggestion_id, + :full_keyword_id, + :rank + )", + named_params! { + ":keyword": keyword.keyword, + ":rank": keyword.rank, + ":full_keyword_id": full_keyword_id, + ":suggestion_id": suggestion_id, + }, )?; } } @@ -834,16 +980,37 @@ impl<'a> SuggestDao<'a> { record_id: &SuggestRecordId, suggestions: &[DownloadedPocketSuggestion], ) -> Result<()> { - let mut suggestion_insert = SuggestionInsertStatement::new(self.conn)?; for suggestion in suggestions { self.scope.err_if_interrupted()?; - let suggestion_id = suggestion_insert.execute( - record_id, - &suggestion.title, - &suggestion.url, - suggestion.score, - SuggestionProvider::Pocket, + let suggestion_id: i64 = self.conn.query_row_and_then_cachable( + &format!( + "INSERT INTO suggestions( + record_id, + provider, + title, + url, + score + ) + VALUES( + :record_id, + {}, + :title, + :url, + :score + ) + RETURNING id", + SuggestionProvider::Pocket as u8 + ), + named_params! { + ":record_id": record_id.as_str(), + ":title": suggestion.title, + ":url": suggestion.url, + ":score": suggestion.score, + }, + |row| row.get(0), + true, )?; + for ((rank, keyword), confidence) in suggestion .high_confidence_keywords .iter() @@ -893,15 +1060,35 @@ impl<'a> SuggestDao<'a> { record_id: &SuggestRecordId, suggestions: &[DownloadedMdnSuggestion], ) -> Result<()> { - let mut suggestion_insert = SuggestionInsertStatement::new(self.conn)?; for suggestion in suggestions { self.scope.err_if_interrupted()?; - let suggestion_id = suggestion_insert.execute( - record_id, - &suggestion.title, - &suggestion.url, - suggestion.score, - SuggestionProvider::Mdn, + let suggestion_id: i64 = self.conn.query_row_and_then_cachable( + &format!( + "INSERT INTO suggestions( + record_id, + provider, + title, + url, + score + ) + VALUES( + :record_id, + {}, + :title, + :url, + :score + ) + RETURNING id", + SuggestionProvider::Mdn as u8 + ), + named_params! { + ":record_id": record_id.as_str(), + ":title": suggestion.title, + ":url": suggestion.url, + ":score": suggestion.score, + }, + |row| row.get(0), + true, )?; self.conn.execute_cached( "INSERT INTO mdn_custom_details( @@ -950,14 +1137,20 @@ impl<'a> SuggestDao<'a> { record_id: &SuggestRecordId, data: &DownloadedWeatherData, ) -> Result<()> { - let mut suggestion_insert = SuggestionInsertStatement::new(self.conn)?; self.scope.err_if_interrupted()?; - let suggestion_id = suggestion_insert.execute( - record_id, - "", - "", - data.weather.score.unwrap_or(DEFAULT_SUGGESTION_SCORE), - SuggestionProvider::Weather, + let suggestion_id: i64 = self.conn.query_row_and_then_cachable( + &format!( + "INSERT INTO suggestions(record_id, provider, title, url, score) + VALUES(:record_id, {}, '', '', :score) + RETURNING id", + SuggestionProvider::Weather as u8 + ), + named_params! { + ":record_id": record_id.as_str(), + ":score": data.weather.score.unwrap_or(DEFAULT_SUGGESTION_SCORE), + }, + |row| row.get(0), + true, )?; for (index, keyword) in data.weather.keywords.iter().enumerate() { self.conn.execute( @@ -999,22 +1192,6 @@ impl<'a> SuggestDao<'a> { Ok(()) } - pub fn insert_dismissal(&self, url: &str) -> Result<()> { - self.conn.execute( - "INSERT OR IGNORE INTO dismissed_suggestions(url) - VALUES(:url)", - named_params! { - ":url": url, - }, - )?; - Ok(()) - } - - pub fn clear_dismissals(&self) -> Result<()> { - self.conn.execute("DELETE FROM dismissed_suggestions", ())?; - Ok(()) - } - /// Deletes all suggestions associated with a Remote Settings record from /// the database. pub fn drop_suggestions(&mut self, record_id: &SuggestRecordId) -> Result<()> { @@ -1210,138 +1387,6 @@ impl<'a> FullKeywordInserter<'a> { } } -// ======================== Statement types ======================== -// -// During ingestion we can insert hundreds of thousands of rows. These types enable speedups by -// allowing us to prepare a statement outside a loop and use it many times inside the loop. -// -// Each type wraps [Connection::prepare] and [Statement] to provide a simplified interface, -// tailored to a specific query. -// -// This pattern is applicable for whenever we execute the same query repeatedly in a loop. -// The impact scales with the number of loop iterations, which is why we currently don't do this -// for providers like Mdn, Pocket, and Weather, which have relatively small number of records -// compared to Amp/Wikipedia. - -struct SuggestionInsertStatement<'conn>(rusqlite::Statement<'conn>); - -impl<'conn> SuggestionInsertStatement<'conn> { - fn new(conn: &'conn Connection) -> Result { - Ok(Self(conn.prepare( - "INSERT INTO suggestions( - record_id, - title, - url, - score, - provider - ) - VALUES(?, ?, ?, ?, ?) - RETURNING id", - )?)) - } - - /// Execute the insert and return the `suggestion_id` for the new row - fn execute( - &mut self, - record_id: &SuggestRecordId, - title: &str, - url: &str, - score: f64, - provider: SuggestionProvider, - ) -> Result { - Ok(self.0.query_row( - (record_id.as_str(), title, url, score, provider as u8), - |row| row.get(0), - )?) - } -} - -struct AmpInsertStatement<'conn>(rusqlite::Statement<'conn>); - -impl<'conn> AmpInsertStatement<'conn> { - fn new(conn: &'conn Connection) -> Result { - Ok(Self(conn.prepare( - "INSERT INTO amp_custom_details( - suggestion_id, - advertiser, - block_id, - iab_category, - impression_url, - click_url, - icon_id - ) - VALUES(?, ?, ?, ?, ?, ?, ?) - ", - )?)) - } - - fn execute(&mut self, suggestion_id: i64, amp: &DownloadedAmpSuggestion) -> Result<()> { - self.0.execute(( - suggestion_id, - &.advertiser, - amp.block_id, - &.iab_category, - &.impression_url, - &.click_url, - &.icon_id, - ))?; - Ok(()) - } -} - -struct WikipediaInsertStatement<'conn>(rusqlite::Statement<'conn>); - -impl<'conn> WikipediaInsertStatement<'conn> { - fn new(conn: &'conn Connection) -> Result { - Ok(Self(conn.prepare( - "INSERT INTO wikipedia_custom_details( - suggestion_id, - icon_id - ) - VALUES(?, ?) - ", - )?)) - } - - fn execute( - &mut self, - suggestion_id: i64, - wikipedia: &DownloadedWikipediaSuggestion, - ) -> Result<()> { - self.0.execute((suggestion_id, &wikipedia.icon_id))?; - Ok(()) - } -} - -struct KeywordInsertStatement<'conn>(rusqlite::Statement<'conn>); - -impl<'conn> KeywordInsertStatement<'conn> { - fn new(conn: &'conn Connection) -> Result { - Ok(Self(conn.prepare( - "INSERT INTO keywords( - suggestion_id, - keyword, - full_keyword_id, - rank - ) - VALUES(?, ?, ?, ?) - ", - )?)) - } - - fn execute( - &mut self, - suggestion_id: i64, - keyword: &str, - full_keyword_id: Option, - rank: usize, - ) -> Result<()> { - self.0 - .execute((suggestion_id, keyword, full_keyword_id, rank))?; - Ok(()) - } -} - fn provider_config_meta_key(provider: SuggestionProvider) -> String { format!("{}{}", PROVIDER_CONFIG_META_KEY_PREFIX, provider as u8) } diff --git a/third_party/rust/suggest/src/lib.rs b/third_party/rust/suggest/src/lib.rs index 15746614d008..23775b7decbd 100644 --- a/third_party/rust/suggest/src/lib.rs +++ b/third_party/rust/suggest/src/lib.rs @@ -4,8 +4,6 @@ */ use remote_settings::RemoteSettingsConfig; -#[cfg(feature = "benchmark_api")] -pub mod benchmarks; mod config; mod db; mod error; @@ -28,7 +26,7 @@ pub(crate) type Result = std::result::Result; pub type SuggestApiResult = std::result::Result; /// A query for suggestions to show in the address bar. -#[derive(Clone, Debug, Default)] +#[derive(Debug, Default)] pub struct SuggestionQuery { pub keyword: String, pub providers: Vec, diff --git a/third_party/rust/suggest/src/rs.rs b/third_party/rust/suggest/src/rs.rs index 4a733ece9df9..a403c1004c8f 100644 --- a/third_party/rust/suggest/src/rs.rs +++ b/third_party/rust/suggest/src/rs.rs @@ -119,7 +119,7 @@ pub(crate) enum SuggestRecord { /// Enum for the different record types that can be consumed. /// Extracting this from the serialization enum so that we can /// extend it to get type metadata. -#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)] +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord)] pub enum SuggestRecordType { Icon, AmpWikipedia, diff --git a/third_party/rust/suggest/src/schema.rs b/third_party/rust/suggest/src/schema.rs index b304363de500..025a959054b9 100644 --- a/third_party/rust/suggest/src/schema.rs +++ b/third_party/rust/suggest/src/schema.rs @@ -15,7 +15,7 @@ use sql_support::open_database::{self, ConnectionInitializer}; /// [`SuggestConnectionInitializer::upgrade_from`]. /// a. If suggestions should be re-ingested after the migration, call `clear_database()` inside /// the migration. -pub const VERSION: u32 = 18; +pub const VERSION: u32 = 17; /// The current Suggest database schema. pub const SQL: &str = " @@ -124,8 +124,10 @@ pub const SQL: &str = " FOREIGN KEY(suggestion_id) REFERENCES suggestions(id) ON DELETE CASCADE ); + -- Just store the MD5 hash of the dismissed suggestion. The collision rate is low and the + -- impact of a collision is not showing a suggestion, which is not that bad. CREATE TABLE dismissed_suggestions ( - url TEXT PRIMARY KEY + url_hash INTEGER PRIMARY KEY ) WITHOUT ROWID; "; @@ -173,17 +175,6 @@ impl ConnectionInitializer for SuggestConnectionInitializer { )?; Ok(()) } - 17 => { - tx.execute( - " - DROP TABLE dismissed_suggestions; - CREATE TABLE dismissed_suggestions ( - url TEXT PRIMARY KEY - ) WITHOUT ROWID;", - (), - )?; - Ok(()) - } _ => Err(open_database::Error::IncompatibleVersion(version)), } } diff --git a/third_party/rust/suggest/src/store.rs b/third_party/rust/suggest/src/store.rs index c55cffc7f52f..4c925e5482d1 100644 --- a/third_party/rust/suggest/src/store.rs +++ b/third_party/rust/suggest/src/store.rs @@ -189,22 +189,6 @@ impl SuggestStore { self.inner.query(query) } - /// Dismiss a suggestion - /// - /// Dismissed suggestions will not be returned again - /// - /// In the case of AMP suggestions this should be the raw URL. - #[handle_error(Error)] - pub fn dismiss_suggestion(&self, suggestion_url: String) -> SuggestApiResult<()> { - self.inner.dismiss_suggestion(suggestion_url) - } - - /// Clear dismissed suggestions - #[handle_error(Error)] - pub fn clear_dismissed_suggestions(&self) -> SuggestApiResult<()> { - self.inner.clear_dismissed_suggestions() - } - /// Interrupts any ongoing queries. /// /// This should be called when the user types new input into the address @@ -269,7 +253,7 @@ pub(crate) struct SuggestStoreInner { } impl SuggestStoreInner { - pub fn new(data_path: impl Into, settings_client: S) -> Self { + fn new(data_path: impl Into, settings_client: S) -> Self { Self { data_path: data_path.into(), dbs: OnceCell::new(), @@ -291,17 +275,6 @@ impl SuggestStoreInner { self.dbs()?.reader.read(|dao| dao.fetch_suggestions(&query)) } - fn dismiss_suggestion(&self, suggestion_url: String) -> Result<()> { - self.dbs()? - .writer - .write(|dao| dao.insert_dismissal(&suggestion_url)) - } - - fn clear_dismissed_suggestions(&self) -> Result<()> { - self.dbs()?.writer.write(|dao| dao.clear_dismissals())?; - Ok(()) - } - fn interrupt(&self) { if let Some(dbs) = self.dbs.get() { // Only interrupt if the databases are already open. @@ -331,7 +304,7 @@ impl SuggestStoreInner where S: SuggestRemoteSettingsClient, { - pub fn ingest(&self, constraints: SuggestIngestionConstraints) -> Result<()> { + fn ingest(&self, constraints: SuggestIngestionConstraints) -> Result<()> { let writer = &self.dbs()?.writer; if let Some(unparsable_records) = @@ -346,7 +319,7 @@ where for unparsable_ids in all_unparsable_ids.chunks(UNPARSABLE_IDS_PER_REQUEST) { let mut options = GetItemsOptions::new(); for unparsable_id in unparsable_ids { - options.filter_eq("id", *unparsable_id); + options.eq("id", *unparsable_id); } let records_chunk = self .settings_client @@ -388,7 +361,7 @@ where // so that we can eventually resume downloading where we left off. options.sort("last_modified", SortOrder::Ascending); - options.filter_eq("type", ingest_record_type.to_string()); + options.eq("type", ingest_record_type.to_string()); // Get the last ingest value. This is the max of the last_ingest_keys // that are in the database. @@ -397,7 +370,7 @@ where { // Only download changes since our last ingest. If our last ingest // was interrupted, we'll pick up where we left off. - options.filter_gt("last_modified", last_ingest.to_string()); + options.gt("last_modified", last_ingest.to_string()); } if let Some(max_suggestions) = constraints.max_suggestions { @@ -602,55 +575,6 @@ where } } -#[cfg(feature = "benchmark_api")] -impl SuggestStoreInner -where - S: SuggestRemoteSettingsClient, -{ - pub fn into_settings_client(self) -> S { - self.settings_client - } - - pub fn ensure_db_initialized(&self) { - self.dbs().unwrap(); - } - - pub fn benchmark_ingest_records_by_type(&self, ingest_record_type: SuggestRecordType) { - self.ingest_records_by_type( - ingest_record_type, - &self.dbs().unwrap().writer, - &SuggestIngestionConstraints::default(), - ) - .unwrap() - } - - pub fn table_row_counts(&self) -> Vec<(String, u32)> { - use sql_support::ConnExt; - - // Note: since this is just used for debugging, use unwrap to simplify the error handling. - let reader = &self.dbs().unwrap().reader; - let conn = reader.conn.lock(); - let table_names: Vec = conn - .query_rows_and_then( - "SELECT name FROM sqlite_master where type = 'table'", - (), - |row| row.get(0), - ) - .unwrap(); - let mut table_names_with_counts: Vec<(String, u32)> = table_names - .into_iter() - .map(|name| { - let count: u32 = conn - .query_one(&format!("SELECT COUNT(*) FROM {name}")) - .unwrap(); - (name, count) - }) - .collect(); - table_names_with_counts.sort_by(|a, b| (b.1.cmp(&a.1))); - table_names_with_counts - } -} - /// Holds a store's open connections to the Suggest database. struct SuggestStoreDbs { /// A read-write connection used to update the database with new data. @@ -5021,10 +4945,10 @@ mod tests { UnparsableRecords( { "clippy-2": UnparsableRecord { - schema_version: 18, + schema_version: 17, }, "fancy-new-suggestions-1": UnparsableRecord { - schema_version: 18, + schema_version: 17, }, }, ), @@ -5093,10 +5017,10 @@ mod tests { UnparsableRecords( { "clippy-2": UnparsableRecord { - schema_version: 18, + schema_version: 17, }, "fancy-new-suggestions-1": UnparsableRecord { - schema_version: 18, + schema_version: 17, }, }, ), @@ -5292,10 +5216,10 @@ mod tests { UnparsableRecords( { "clippy-2": UnparsableRecord { - schema_version: 18, + schema_version: 17, }, "fancy-new-suggestions-1": UnparsableRecord { - schema_version: 18, + schema_version: 17, }, }, ), @@ -5381,7 +5305,7 @@ mod tests { UnparsableRecords( { "invalid-attachment": UnparsableRecord { - schema_version: 18, + schema_version: 17, }, }, ), @@ -6032,204 +5956,4 @@ mod tests { Ok(()) } - - #[test] - fn remove_dismissed_suggestions() -> anyhow::Result<()> { - before_each(); - - let snapshot = Snapshot::with_records(json!([{ - "id": "data-1", - "type": "data", - "last_modified": 15, - "attachment": { - "filename": "data-1.json", - "mimetype": "application/json", - "location": "data-1.json", - "hash": "", - "size": 0, - }, - - }, { - "id": "data-2", - "type": "amo-suggestions", - "last_modified": 15, - "attachment": { - "filename": "data-2.json", - "mimetype": "application/json", - "location": "data-2.json", - "hash": "", - "size": 0, - }, - }, { - "id": "data-3", - "type": "pocket-suggestions", - "last_modified": 15, - "attachment": { - "filename": "data-3.json", - "mimetype": "application/json", - "location": "data-3.json", - "hash": "", - "size": 0, - }, - }, { - "id": "data-5", - "type": "mdn-suggestions", - "last_modified": 15, - "attachment": { - "filename": "data-5.json", - "mimetype": "application/json", - "location": "data-5.json", - "hash": "", - "size": 0, - }, - }, { - "id": "data-6", - "type": "amp-mobile-suggestions", - "last_modified": 15, - "attachment": { - "filename": "data-6.json", - "mimetype": "application/json", - "location": "data-6.json", - "hash": "", - "size": 0, - }, - }, { - "id": "icon-2", - "type": "icon", - "last_modified": 20, - "attachment": { - "filename": "icon-2.png", - "mimetype": "image/png", - "location": "icon-2.png", - "hash": "", - "size": 0, - }, - }, { - "id": "icon-3", - "type": "icon", - "last_modified": 25, - "attachment": { - "filename": "icon-3.png", - "mimetype": "image/png", - "location": "icon-3.png", - "hash": "", - "size": 0, - }, - }]))? - .with_data( - "data-1.json", - json!([{ - "id": 0, - "advertiser": "Good Place Eats", - "iab_category": "8 - Food & Drink", - "keywords": ["cats"], - "title": "Lasagna Come Out Tomorrow", - "url": "https://www.lasagna.restaurant", - "icon": "2", - "impression_url": "https://example.com/impression_url", - "click_url": "https://example.com/click_url", - "score": 0.31 - }, { - "id": 0, - "advertiser": "Wikipedia", - "iab_category": "5 - Education", - "keywords": ["cats"], - "title": "California", - "url": "https://wikipedia.org/California", - "icon": "3" - }]), - )? - .with_data( - "data-2.json", - json!([ - { - "description": "amo suggestion", - "url": "https://addons.mozilla.org/en-US/firefox/addon/example", - "guid": "{b9db16a4-6edc-47ec-a1f4-b86292ed211d}", - "keywords": ["cats"], - "title": "Firefox Relay", - "icon": "https://addons.mozilla.org/user-media/addon_icons/2633/2633704-64.png?modified=2c11a80b", - "rating": "4.9", - "number_of_ratings": 888, - "score": 0.32 - }, - ]), - )? - .with_data( - "data-3.json", - json!([ - { - "description": "pocket suggestion", - "url": "https://getpocket.com/collections/its-not-just-burnout-how-grind-culture-failed-women", - "lowConfidenceKeywords": [], - "highConfidenceKeywords": ["cats"], - "title": "‘It’s Not Just Burnout:’ How Grind Culture Fails Women", - "score": 0.33 - }, - ]), - )? - .with_data( - "data-5.json", - json!([ - { - "description": "Javascript Array", - "url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array", - "keywords": ["cats"], - "title": "Array", - "score": 0.24 - }, - ]), - )? - .with_data( - "data-6.json", - json!([ - { - "id": 0, - "advertiser": "Good Place Eats", - "iab_category": "8 - Food & Drink", - "keywords": ["cats"], - "title": "Mobile - Lasagna Come Out Tomorrow", - "url": "https://www.lasagna.restaurant", - "icon": "3", - "impression_url": "https://example.com/impression_url", - "click_url": "https://example.com/click_url", - "score": 0.26 - } - ]), - )? - .with_icon("icon-2.png", "i-am-an-icon".as_bytes().into()) - .with_icon("icon-3.png", "also-an-icon".as_bytes().into()); - - let store = unique_test_store(SnapshotSettingsClient::with_snapshot(snapshot)); - store.ingest(SuggestIngestionConstraints::default())?; - - // A query for cats should return all suggestions - let query = SuggestionQuery { - keyword: "cats".into(), - providers: vec![ - SuggestionProvider::Amp, - SuggestionProvider::Wikipedia, - SuggestionProvider::Amo, - SuggestionProvider::Pocket, - SuggestionProvider::Mdn, - SuggestionProvider::AmpMobile, - ], - limit: None, - }; - let results = store.query(query.clone())?; - assert_eq!(results.len(), 6); - - for result in results { - store.dismiss_suggestion(result.raw_url().unwrap().to_string())?; - } - - // After dismissing the suggestions, the next query shouldn't return them - assert_eq!(store.query(query.clone())?.len(), 0); - - // Clearing the dismissals should cause them to be returned again - store.clear_dismissed_suggestions()?; - assert_eq!(store.query(query.clone())?.len(), 6); - - Ok(()) - } } diff --git a/third_party/rust/suggest/src/suggest.udl b/third_party/rust/suggest/src/suggest.udl index 4a4e3fe9a058..133cc56f141d 100644 --- a/third_party/rust/suggest/src/suggest.udl +++ b/third_party/rust/suggest/src/suggest.udl @@ -123,12 +123,6 @@ interface SuggestStore { [Throws=SuggestApiError] sequence query(SuggestionQuery query); - [Throws=SuggestApiError] - void dismiss_suggestion(string raw_suggestion_url); - - [Throws=SuggestApiError] - void clear_dismissed_suggestions(); - void interrupt(); [Throws=SuggestApiError] diff --git a/third_party/rust/suggest/src/suggestion.rs b/third_party/rust/suggest/src/suggestion.rs index c0b45524c739..02a169df15f5 100644 --- a/third_party/rust/suggest/src/suggestion.rs +++ b/third_party/rust/suggest/src/suggestion.rs @@ -109,37 +109,6 @@ impl Ord for Suggestion { } } -impl Suggestion { - /// Get the URL for this suggestion, if present - pub fn url(&self) -> Option<&str> { - match self { - Self::Amp { url, .. } - | Self::Pocket { url, .. } - | Self::Wikipedia { url, .. } - | Self::Amo { url, .. } - | Self::Yelp { url, .. } - | Self::Mdn { url, .. } => Some(url), - _ => None, - } - } - - /// Get the raw URL for this suggestion, if present - /// - /// This is the same as `url` except for Amp. In that case, `url` is the URL after being - /// "cooked" using template interpolation, while `raw_url` is the URL template. - pub fn raw_url(&self) -> Option<&str> { - match self { - Self::Amp { raw_url: url, .. } - | Self::Pocket { url, .. } - | Self::Wikipedia { url, .. } - | Self::Amo { url, .. } - | Self::Yelp { url, .. } - | Self::Mdn { url, .. } => Some(url), - _ => None, - } - } -} - impl Eq for Suggestion {} /// Replaces all template parameters in a "raw" sponsored suggestion URL, /// producing a "cooked" URL with real values. diff --git a/third_party/rust/sync15/.cargo-checksum.json b/third_party/rust/sync15/.cargo-checksum.json index 723c4c4384e1..5f995892d5da 100644 --- a/third_party/rust/sync15/.cargo-checksum.json +++ b/third_party/rust/sync15/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"6827fe696bd5e7ef806389493be837c7fa87f3301a7b243890259c5304fda21f","README.md":"6d4ff5b079ac5340d18fa127f583e7ad793c5a2328b8ecd12c3fc723939804f2","build.rs":"aa971160d67ce8626b26e15c04c34b730f594c45c817aae34cfc9f3ea14ae284","src/bso/content.rs":"92935258745bdf0c3915a555cb6884a7fa69faa1290ec2c1815f6e2f3c0f0562","src/bso/crypto.rs":"27602dcccb37d3a55620ee4e16b705da455d49af575de115c7c79c0178eb1d6d","src/bso/mod.rs":"09e723dc7e99295ecafdcadffaf604d66ea27cf2b7f1fd9ab3cac4f4698ff6a7","src/bso/test_utils.rs":"4ec5a2df5e1c0ec14dc770681e959bdcef6ef04f6fde435999197f46a8ae4831","src/client/coll_state.rs":"13e6ef55273baf5536acc369be522e34a803a32cabf19cce43e426aea9b6223e","src/client/coll_update.rs":"dac04a90c29dd969f8b4250414609c9b6d61daf2dfa4ae77d1c4a165ba970b05","src/client/collection_keys.rs":"c27b2277a3a52033b58ab01490fc2ea7007494195dd5e6dc2c6931a4ca96795a","src/client/mod.rs":"8f588d4a035cf79d96f2500f06d5651c1a7c566127c456ffa5429811ddce3fd6","src/client/request.rs":"8841524e37d8195867bdf6ba98c75f610cf47a4644adeebd6372cc6713f2260a","src/client/state.rs":"4e31193ef2471c1dfabf1c6a391bcb95e14ddb45855786a4194ff187d5c9347c","src/client/status.rs":"f445a8765dac9789444e23b5145148413407bb1d18a15ef56682243997f591bf","src/client/storage_client.rs":"8de72d4ba3ca4f68c8e1898466de83a2b543545a18679800cb4f7fbda2dc3183","src/client/sync.rs":"b29abb512ec9d163f7883b71f78c9202802dcb17cad1fc5dc08087fb0bb66704","src/client/sync_multiple.rs":"6e92571132f89744b553190c596be8aff9b2d031d8f79d82c94cdf78b1683f4a","src/client/token.rs":"b268759d31e0fe17e0e2a428694cd9a317fcfbdd52f023d5d8c7cc6f00f1a102","src/client/util.rs":"71cc70ee41f821f53078675e636e9fad9c6046fa1a989e37f5487e340a2277d6","src/client_types.rs":"3c3cac1540b92482f43660d9e43bdde8481c4cc1a98253a68c80e791231f5976","src/clients_engine/engine.rs":"9e11b47be81fc63214f31879af74075674aa50a8f8989afe20fefa7990fa99b9","src/clients_engine/mod.rs":"461729e6f89b66b2cbd89b041a03d4d6a8ba582284ed4f3015cb13e1a0c6da97","src/clients_engine/record.rs":"b0d84bf420743d7638a45e4836633a45e50257d5548fe7ecd04bff4d724439b8","src/clients_engine/ser.rs":"ef12daeb11faf618fe3cafe91f20a031fe5bb6751369b6ee5aee03f196efe88c","src/device_type.rs":"dc2d4296d25e31471c8e68488f1043ff239b902036cd6aea8a686cf79b4ed335","src/enc_payload.rs":"aa3eea7df49b24cd59831680a47c417b73a3e36e6b0f3f4baf14ca66bd68be6b","src/engine/bridged_engine.rs":"f70f1bfce6e0c04b0c72ec9cbfbb12c82d4009a23fb9768792107d41b2865a4f","src/engine/mod.rs":"90f1f9760f5f712a337aebb04e59c736e4b6fbd89d6a188d969210c7f3f321ae","src/engine/request.rs":"5923025fb9550178339f880a1bf8526d8e853e7a0b2bce6d9d687cc808ac0085","src/engine/sync_engine.rs":"531b35d72ce9e04c3e543c0468c1e450fba2c0dc3d33d68d9b1c0a5c1ad7dd34","src/error.rs":"a45cfe02e6301f473c34678b694943c1a04308b8c292c6e0448bf495194c3b5e","src/key_bundle.rs":"abd0781f3be8c8e7c691f18bb71f3433b633803c48da9794e15ac6301ed60d6c","src/lib.rs":"f59f8817978d943518dfa03ab31fc0f6b1fc72ee9943a97aef1537e2769649f5","src/record_types.rs":"02bb3d352fb808131d298f9b90d9c95b7e9e0138b97c5401f3b9fdacc5562f44","src/server_timestamp.rs":"6272299c92b05b9ec9dc2e18402ebe927b07ccf1dcab5082301a09e0ee56ce24","src/sync15.udl":"005b2b056b93c959a04670f6f489afecb8e17093d8e4be34765a3a4cc0faeb8c","src/telemetry.rs":"e3a7e13e85f5e336526ebf07db04c81b8f1ba89ae1db4159a3a570826cb8cfd2","uniffi.toml":"34488f947497a9b05007445dd816024ef02e6b1696f1056ee868f039722828ee"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"739abc68b38e8468c5d1eb3f7a66f01e638765f9d8714080e07817f0939a2b66","README.md":"6d4ff5b079ac5340d18fa127f583e7ad793c5a2328b8ecd12c3fc723939804f2","build.rs":"aa971160d67ce8626b26e15c04c34b730f594c45c817aae34cfc9f3ea14ae284","src/bso/content.rs":"92935258745bdf0c3915a555cb6884a7fa69faa1290ec2c1815f6e2f3c0f0562","src/bso/crypto.rs":"27602dcccb37d3a55620ee4e16b705da455d49af575de115c7c79c0178eb1d6d","src/bso/mod.rs":"09e723dc7e99295ecafdcadffaf604d66ea27cf2b7f1fd9ab3cac4f4698ff6a7","src/bso/test_utils.rs":"4ec5a2df5e1c0ec14dc770681e959bdcef6ef04f6fde435999197f46a8ae4831","src/client/coll_state.rs":"13e6ef55273baf5536acc369be522e34a803a32cabf19cce43e426aea9b6223e","src/client/coll_update.rs":"dac04a90c29dd969f8b4250414609c9b6d61daf2dfa4ae77d1c4a165ba970b05","src/client/collection_keys.rs":"c27b2277a3a52033b58ab01490fc2ea7007494195dd5e6dc2c6931a4ca96795a","src/client/mod.rs":"8f588d4a035cf79d96f2500f06d5651c1a7c566127c456ffa5429811ddce3fd6","src/client/request.rs":"8841524e37d8195867bdf6ba98c75f610cf47a4644adeebd6372cc6713f2260a","src/client/state.rs":"4e31193ef2471c1dfabf1c6a391bcb95e14ddb45855786a4194ff187d5c9347c","src/client/status.rs":"f445a8765dac9789444e23b5145148413407bb1d18a15ef56682243997f591bf","src/client/storage_client.rs":"8de72d4ba3ca4f68c8e1898466de83a2b543545a18679800cb4f7fbda2dc3183","src/client/sync.rs":"b29abb512ec9d163f7883b71f78c9202802dcb17cad1fc5dc08087fb0bb66704","src/client/sync_multiple.rs":"6e92571132f89744b553190c596be8aff9b2d031d8f79d82c94cdf78b1683f4a","src/client/token.rs":"b268759d31e0fe17e0e2a428694cd9a317fcfbdd52f023d5d8c7cc6f00f1a102","src/client/util.rs":"71cc70ee41f821f53078675e636e9fad9c6046fa1a989e37f5487e340a2277d6","src/client_types.rs":"3c3cac1540b92482f43660d9e43bdde8481c4cc1a98253a68c80e791231f5976","src/clients_engine/engine.rs":"9e11b47be81fc63214f31879af74075674aa50a8f8989afe20fefa7990fa99b9","src/clients_engine/mod.rs":"461729e6f89b66b2cbd89b041a03d4d6a8ba582284ed4f3015cb13e1a0c6da97","src/clients_engine/record.rs":"b0d84bf420743d7638a45e4836633a45e50257d5548fe7ecd04bff4d724439b8","src/clients_engine/ser.rs":"ef12daeb11faf618fe3cafe91f20a031fe5bb6751369b6ee5aee03f196efe88c","src/device_type.rs":"dc2d4296d25e31471c8e68488f1043ff239b902036cd6aea8a686cf79b4ed335","src/enc_payload.rs":"aa3eea7df49b24cd59831680a47c417b73a3e36e6b0f3f4baf14ca66bd68be6b","src/engine/bridged_engine.rs":"f70f1bfce6e0c04b0c72ec9cbfbb12c82d4009a23fb9768792107d41b2865a4f","src/engine/mod.rs":"90f1f9760f5f712a337aebb04e59c736e4b6fbd89d6a188d969210c7f3f321ae","src/engine/request.rs":"5923025fb9550178339f880a1bf8526d8e853e7a0b2bce6d9d687cc808ac0085","src/engine/sync_engine.rs":"531b35d72ce9e04c3e543c0468c1e450fba2c0dc3d33d68d9b1c0a5c1ad7dd34","src/error.rs":"a45cfe02e6301f473c34678b694943c1a04308b8c292c6e0448bf495194c3b5e","src/key_bundle.rs":"abd0781f3be8c8e7c691f18bb71f3433b633803c48da9794e15ac6301ed60d6c","src/lib.rs":"f59f8817978d943518dfa03ab31fc0f6b1fc72ee9943a97aef1537e2769649f5","src/record_types.rs":"02bb3d352fb808131d298f9b90d9c95b7e9e0138b97c5401f3b9fdacc5562f44","src/server_timestamp.rs":"6272299c92b05b9ec9dc2e18402ebe927b07ccf1dcab5082301a09e0ee56ce24","src/sync15.udl":"005b2b056b93c959a04670f6f489afecb8e17093d8e4be34765a3a4cc0faeb8c","src/telemetry.rs":"e3a7e13e85f5e336526ebf07db04c81b8f1ba89ae1db4159a3a570826cb8cfd2","uniffi.toml":"34488f947497a9b05007445dd816024ef02e6b1696f1056ee868f039722828ee"},"package":null} \ No newline at end of file diff --git a/third_party/rust/sync15/Cargo.toml b/third_party/rust/sync15/Cargo.toml index 943bee58ae9d..86f7da91f85d 100644 --- a/third_party/rust/sync15/Cargo.toml +++ b/third_party/rust/sync15/Cargo.toml @@ -30,7 +30,7 @@ serde_derive = "1" serde_json = "1" serde_path_to_error = "0.1" thiserror = "1.0" -uniffi = "0.27.1" +uniffi = "0.25.2" [dependencies.base16] version = "0.2" @@ -72,7 +72,7 @@ version = "0.10" default-features = false [build-dependencies.uniffi] -version = "0.27.1" +version = "0.25.2" features = ["build"] [features] diff --git a/third_party/rust/tabs/.cargo-checksum.json b/third_party/rust/tabs/.cargo-checksum.json index a9adbf92141c..1f1fa20bfa4b 100644 --- a/third_party/rust/tabs/.cargo-checksum.json +++ b/third_party/rust/tabs/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"73ac434bafd302d09e8b61742cdb094db767985f0cbae7d00efb5096a33dea4b","README.md":"c48b8f391ef822c4f3971b5f453a1e7b43bea232752d520460d2f04803aead1a","build.rs":"33e61b811b19ed2b58e319cc65d5988bed258d2c4fea2d706301184c59847a0f","src/error.rs":"2694657aeb12f99c4b2fe102ad2b08b79955d209201831b3e071129f0b7d7eda","src/lib.rs":"7208f78955e015ef8bab7916307e551cd3c1bd56d7fe14f8b53cd53bc4b38555","src/schema.rs":"2b7b51f3c2edc0ca603495c10b917603fd9ac791c4a366080e40d090b13b91f2","src/storage.rs":"18f449b6daf1641dc351be451311495b7c05e16c4e2d4eaf12c1fa02fa750b67","src/store.rs":"ab0b6214b30b0f0fa7c6a89098ff3db1a8f76264f6711c4481c0be460afe522b","src/sync/bridge.rs":"18d3a7913a030b598d4b6cbd5b7e2ab4cef4cc7ea964f5bc84d7fb2f28787529","src/sync/engine.rs":"2d14d899a38ac72b9141d505babd94ef7b6fbc5a95be70f324a40bf01935793d","src/sync/mod.rs":"09ba3c87f1174a243bf5aaa481effd18929d54359ceb9b23ccb2c32ee3482f34","src/sync/record.rs":"eef6751c209d039958afbe245ddb006cfdf6b8b6b47f925f69c552b832b87922","src/tabs.udl":"2cefc7f6a27b5619bc536d4a19608cf24153d745199fbeaf192e24b4381dedfb","uniffi.toml":"f9125e8d55b109e86076ee88bfd640372f06b142b7db557e41816c7227dd445c"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"c06aa10f3dfa7be35c4fb54cb629704826da5bd9d08eaf09211343bb2b62bf74","README.md":"c48b8f391ef822c4f3971b5f453a1e7b43bea232752d520460d2f04803aead1a","build.rs":"33e61b811b19ed2b58e319cc65d5988bed258d2c4fea2d706301184c59847a0f","src/error.rs":"2694657aeb12f99c4b2fe102ad2b08b79955d209201831b3e071129f0b7d7eda","src/lib.rs":"7208f78955e015ef8bab7916307e551cd3c1bd56d7fe14f8b53cd53bc4b38555","src/schema.rs":"2b7b51f3c2edc0ca603495c10b917603fd9ac791c4a366080e40d090b13b91f2","src/storage.rs":"18f449b6daf1641dc351be451311495b7c05e16c4e2d4eaf12c1fa02fa750b67","src/store.rs":"ab0b6214b30b0f0fa7c6a89098ff3db1a8f76264f6711c4481c0be460afe522b","src/sync/bridge.rs":"18d3a7913a030b598d4b6cbd5b7e2ab4cef4cc7ea964f5bc84d7fb2f28787529","src/sync/engine.rs":"2d14d899a38ac72b9141d505babd94ef7b6fbc5a95be70f324a40bf01935793d","src/sync/mod.rs":"09ba3c87f1174a243bf5aaa481effd18929d54359ceb9b23ccb2c32ee3482f34","src/sync/record.rs":"eef6751c209d039958afbe245ddb006cfdf6b8b6b47f925f69c552b832b87922","src/tabs.udl":"2cefc7f6a27b5619bc536d4a19608cf24153d745199fbeaf192e24b4381dedfb","uniffi.toml":"f9125e8d55b109e86076ee88bfd640372f06b142b7db557e41816c7227dd445c"},"package":null} \ No newline at end of file diff --git a/third_party/rust/tabs/Cargo.toml b/third_party/rust/tabs/Cargo.toml index 84a5c7ad3330..c06ad84ca98f 100644 --- a/third_party/rust/tabs/Cargo.toml +++ b/third_party/rust/tabs/Cargo.toml @@ -29,7 +29,7 @@ serde = "1" serde_derive = "1" serde_json = "1" thiserror = "1.0" -uniffi = "0.27.1" +uniffi = "0.25.2" url = "2.1" [dependencies.error-support] @@ -65,5 +65,5 @@ features = ["humantime"] default-features = false [build-dependencies.uniffi] -version = "0.27.1" +version = "0.25.2" features = ["build"] diff --git a/third_party/rust/textwrap/.cargo-checksum.json b/third_party/rust/textwrap/.cargo-checksum.json deleted file mode 100644 index 09486838281c..000000000000 --- a/third_party/rust/textwrap/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"2b49672ca15da27844abb6643660faa3a517b1b731c7c5023a55de2e570f35fb","Cargo.lock":"c60631b9ccb2798984507f9e074ce15d9b6e59f34d4dc3418ef40c222ac55725","Cargo.toml":"bccd38e75da62b89a7bb2d741926688f1822ecd5165a703ffaadf9177a34e919","LICENSE":"ce93600c49fbb3e14df32efe752264644f6a2f8e08a735ba981725799e5309ef","README.md":"5dd8128a4e9057aeb6133a073d30a819230243907e717349101b41a11ec23234","rustfmt.toml":"02637ad90caa19885b25b1ce8230657b3703402775d9db83687a3f55de567509","src/columns.rs":"73432251f95ac0b84d5e971989ebc5f867d8b8ca82d5e3fc67fe3a66216fbc38","src/core.rs":"e2cc6b1e5978df0db9b6d0425e7d0ebf65dd188aff90df800f1f2dda7b1c53f2","src/fill.rs":"1fe773dad2d0bb67a7739b3931c1ee3269d677b71a0716dcdb5b01fe2539d7c2","src/fuzzing.rs":"0a77010a555a244ac5e907754b2104912299815009922cfdc0f6b48d92135295","src/indentation.rs":"f41ee8be41e01620c7d88b76f81a01ce6a619939505eaf3fcfe6c8021fae022b","src/lib.rs":"d5d39085faa4527bf6c16a91c5a44b9b894e3f3a2606763bceac22038528c28c","src/line_ending.rs":"bf416f683ab952d4df75d5dc3c199e7ae7740db2c5982ac1a20c3f4b186ded76","src/options.rs":"0d3aec6ab238f3aa14aa57e736384ec208cd3013373941c76d66c0125ca0630f","src/refill.rs":"33ce98ef31c4791893fc2136edd8f8d95cdd38fa54daa59aaf078b359c43d913","src/termwidth.rs":"2e7854e822c435341bc4d467d13614d417df4f2f530cea3c5e49e3b44e754943","src/word_separators.rs":"d3b2b5faf224bf414bf9da48be02eaffb41aec3a91674bedab02ad5748344143","src/word_splitters.rs":"8de2b92eff6d752e321f219136b45b9812267b5be7ace57602a3bb9d3b5cf332","src/wrap.rs":"52c48e2e5155100e4067363e56b180785684bca3109c95c3425ef8051738ff0e","src/wrap_algorithms.rs":"c99498f2e58634f707545ba73c3a99025086d1afb8c12aeceff2ced2887bb8ae","src/wrap_algorithms/optimal_fit.rs":"a9ce8bad61d4fa81df9e292a557fbf5303df78391d63610ec512b9b06f9193b1","tests/indent.rs":"51f977db11632a32fafecf86af88413d51238fe6efcf18ec52fac89133714278","tests/version-numbers.rs":"9e964f58dbdf051fc6fe0d6542ab312d3e95f26c3fd14bce84449bb625e45761"},"package":"23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"} \ No newline at end of file diff --git a/third_party/rust/textwrap/CHANGELOG.md b/third_party/rust/textwrap/CHANGELOG.md deleted file mode 100644 index 362c0c0b9da2..000000000000 --- a/third_party/rust/textwrap/CHANGELOG.md +++ /dev/null @@ -1,616 +0,0 @@ -# Changelog - -This file lists the most important changes made in each release of -`textwrap`. - -## Version 0.16.1 (2024-02-17) - -This release fixes `display_width` to ignore inline-hyperlinks. The minimum -supported version of Rust is now documented to be 1.56. - -* [#526](https://github.com/mgeisler/textwrap/pull/526): Ignore ANSI hyperlinks - in `display_width`: calculations. -* [#521](https://github.com/mgeisler/textwrap/pull/521): Add `Options::width` - setter method. -* [#520](https://github.com/mgeisler/textwrap/pull/520): Clarify that - `WordSeparator` is an enum rather than a trait. -* [#518](https://github.com/mgeisler/textwrap/pull/518): Test with latest stable - and nightly Rust, but check that we can build with Rust 1.56. - -## Version 0.16.0 (2022-10-23) - -This release marks `Options` as `non_exhaustive` and extends it to -make line endings configurable, it adds new fast paths to `fill` and -`wrap`, and it fixes crashes in `unfill` and `refill`. - -* [#480](https://github.com/mgeisler/textwrap/pull/480): Mark - `Options` as `non_exhaustive`. This will allow us to extend the - struct in the future without breaking backwards compatibility. -* [#478](https://github.com/mgeisler/textwrap/pull/478): Add fast - paths to `fill` and `wrap`. This makes the functions 10-25 times - faster when the no wrapping is needed. -* [#468](https://github.com/mgeisler/textwrap/pull/468): Fix `refill` - to add back correct line ending. -* [#467](https://github.com/mgeisler/textwrap/pull/467): Fix crashes - in `unfill` and `refill`. -* [#458](https://github.com/mgeisler/textwrap/pull/458): Test with - Rust 1.56 (first compiler release with support for Rust 2021). -* [#454](https://github.com/mgeisler/textwrap/pull/454): Make line - endings configurable. -* [#448](https://github.com/mgeisler/textwrap/pull/448): Migrate to - the Rust 2021 edition. - -## Version 0.15.2 (2022-10-24) - -This release is identical to 0.15.0 and is only there to give people a -way to install crates which depend on the yanked 0.15.1 release. See -[#484](https://github.com/mgeisler/textwrap/issues/484) for details. - -## Version 0.15.1 (2022-09-15) - -This release was yanked since it accidentally broke backwards -compatibility with 0.15.0. - -## Version 0.15.0 (2022-02-27) - -This is a major feature release with two main changes: - -* [#421](https://github.com/mgeisler/textwrap/pull/421): Use `f64` - instead of `usize` for fragment widths. - - This fixes problems with overflows in the internal computations of - `wrap_optimal_fit` when fragments (words) or line lengths had - extreme values, such as `usize::MAX`. - -* [#438](https://github.com/mgeisler/textwrap/pull/438): Simplify - `Options` by removing generic type parameters. - - This change removes the new generic parameters introduced in version - 0.14, as well as the original `WrapSplitter` parameter which has - been present since very early versions. - - The result is a simplification of function and struct signatures - across the board. So what used to be - - ```rust - let options: Options< - wrap_algorithms::FirstFit, - word_separators::AsciiSpace, - word_splitters::HyphenSplitter, - > = Options::new(80); - ``` - - if types are fully written out, is now simply - - ```rust - let options: Options<'_> = Options::new(80); - ``` - - The anonymous lifetime represent the lifetime of the - `initial_indent` and `subsequent_indent` strings. The change is - nearly performance neutral (a 1-2% regression). - -Smaller improvements and changes: - -* [#404](https://github.com/mgeisler/textwrap/pull/404): Make - documentation for short last-line penalty more precise. -* [#405](https://github.com/mgeisler/textwrap/pull/405): Cleanup and - simplify `Options` docstring. -* [#411](https://github.com/mgeisler/textwrap/pull/411): Default to - `OptimalFit` in interactive example. -* [#415](https://github.com/mgeisler/textwrap/pull/415): Add demo - program to help compute binary sizes. -* [#423](https://github.com/mgeisler/textwrap/pull/423): Add fuzz - tests with fully arbitrary fragments. -* [#424](https://github.com/mgeisler/textwrap/pull/424): Change - `wrap_optimal_fit` penalties to non-negative numbers. -* [#430](https://github.com/mgeisler/textwrap/pull/430): Add - `debug-words` example. -* [#432](https://github.com/mgeisler/textwrap/pull/432): Use precise - dependency versions in Cargo.toml. - -## Version 0.14.2 (2021-06-27) - -The 0.14.1 release included more changes than intended and has been -yanked. The change intended for 0.14.1 is now included in 0.14.2. - -## Version 0.14.1 (2021-06-26) - -This release fixes a panic reported by @Makoto, thanks! - -* [#391](https://github.com/mgeisler/textwrap/pull/391): Fix panic in - `find_words` due to string access outside of a character boundary. - -## Version 0.14.0 (2021-06-05) - -This is a major feature release which makes Textwrap more configurable -and flexible. The high-level API of `textwrap::wrap` and -`textwrap::fill` remains unchanged, but low-level structs have moved -around. - -The biggest change is the introduction of new generic type parameters -to the `Options` struct. These parameters lets you statically -configure the wrapping algorithm, the word separator, and the word -splitter. If you previously spelled out the full type for `Options`, -you now need to take the extra type parameters into account. This -means that - -```rust -let options: Options = Options::new(80); -``` - -changes to - -```rust -let options: Options< - wrap_algorithms::FirstFit, - word_separators::AsciiSpace, - word_splitters::HyphenSplitter, -> = Options::new(80); -``` - -This is quite a mouthful, so we suggest using type inference where -possible. You won’t see any chance if you call `wrap` directly with a -width or with an `Options` value constructed on the fly. Please open -an issue if this causes problems for you! - -### New `WordSeparator` Trait - -* [#332](https://github.com/mgeisler/textwrap/pull/332): Add - `WordSeparator` trait to allow customizing how words are found in a - line of text. Until now, Textwrap would always assume that words are - separated by ASCII space characters. You can now customize this as - needed. - -* [#313](https://github.com/mgeisler/textwrap/pull/313): Add support - for using the Unicode line breaking algorithm to find words. This is - done by adding a second implementation of the new `WordSeparator` - trait. The implementation uses the unicode-linebreak crate, which is - a new optional dependency. - - With this, Textwrap can be used with East-Asian languages such as - Chinese or Japanese where there are no spaces between words. - Breaking a long sequence of emojis is another example where line - breaks might be wanted even if there are no whitespace to be found. - Feedback would be appreciated for this feature. - - -### Indent - -* [#353](https://github.com/mgeisler/textwrap/pull/353): Trim trailing - whitespace from `prefix` in `indent`. - - Before, empty lines would get no prefix added. Now, empty lines have - a trimmed prefix added. This little trick makes `indent` much more - useful since you can now safely indent with `"# "` without creating - trailing whitespace in the output due to the trailing whitespace in - your prefix. - -* [#354](https://github.com/mgeisler/textwrap/pull/354): Make `indent` - about 20% faster by preallocating the output string. - - -### Documentation - -* [#308](https://github.com/mgeisler/textwrap/pull/308): Document - handling of leading and trailing whitespace when wrapping text. - -### WebAssembly Demo - -* [#310](https://github.com/mgeisler/textwrap/pull/310): Thanks to - WebAssembly, you can now try out Textwrap directly in your browser. - Please try it out: https://mgeisler.github.io/textwrap/. - -### New Generic Parameters - -* [#331](https://github.com/mgeisler/textwrap/pull/331): Remove outer - boxing from `Options`. - -* [#357](https://github.com/mgeisler/textwrap/pull/357): Replace - `core::WrapAlgorithm` enum with a `wrap_algorithms::WrapAlgorithm` - trait. This allows for arbitrary wrapping algorithms to be plugged - into the library. - -* [#358](https://github.com/mgeisler/textwrap/pull/358): Switch - wrapping functions to use a slice for `line_widths`. - -* [#368](https://github.com/mgeisler/textwrap/pull/368): Move - `WordSeparator` and `WordSplitter` traits to separate modules. - Before, Textwrap had several top-level structs such as - `NoHyphenation` and `HyphenSplitter`. These implementations of - `WordSplitter` now lives in a dedicated `word_splitters` module. - Similarly, we have a new `word_separators` module for - implementations of `WordSeparator`. - -* [#369](https://github.com/mgeisler/textwrap/pull/369): Rename - `Options::splitter` to `Options::word_splitter` for consistency with - the other fields backed by traits. - -## Version 0.13.4 (2021-02-23) - -This release removes `println!` statements which was left behind in -`unfill` by mistake. - -* [#296](https://github.com/mgeisler/textwrap/pull/296): Improve house - building example with more comments. -* [#297](https://github.com/mgeisler/textwrap/pull/297): Remove debug - prints in the new `unfill` function. - -## Version 0.13.3 (2021-02-20) - -This release contains a bugfix for `indent` and improved handling of -emojis. We’ve also added a new function for formatting text in columns -and functions for reformatting already wrapped text. - -* [#276](https://github.com/mgeisler/textwrap/pull/276): Extend - `core::display_width` to handle emojis when the unicode-width Cargo - feature is disabled. -* [#279](https://github.com/mgeisler/textwrap/pull/279): Make `indent` - preserve existing newlines in the input string. Before, - `indent("foo", "")` would return `"foo\n"` by mistake. It now - returns `"foo"` instead. -* [#281](https://github.com/mgeisler/textwrap/pull/281): Ensure all - `Options` fields have examples. -* [#282](https://github.com/mgeisler/textwrap/pull/282): Add a - `wrap_columns` function. -* [#294](https://github.com/mgeisler/textwrap/pull/294): Add new - `unfill` and `refill` functions. - -## Version 0.13.2 (2020-12-30) - -This release primarily makes all dependencies optional. This makes it -possible to slim down textwrap as needed. - -* [#254](https://github.com/mgeisler/textwrap/pull/254): `impl - WordSplitter` for `Box where T: WordSplitter`. -* [#255](https://github.com/mgeisler/textwrap/pull/255): Use command - line arguments as initial text in interactive example. -* [#256](https://github.com/mgeisler/textwrap/pull/256): Introduce - fuzz tests for `wrap_optimal_fit` and `wrap_first_fit`. -* [#260](https://github.com/mgeisler/textwrap/pull/260): Make the - unicode-width dependency optional. -* [#261](https://github.com/mgeisler/textwrap/pull/261): Make the - smawk dependency optional. - -## Version 0.13.1 (2020-12-10) - -This is a bugfix release which fixes a regression in 0.13.0. The bug -meant that colored text was wrapped incorrectly. - -* [#245](https://github.com/mgeisler/textwrap/pull/245): Support - deleting a word with Ctrl-Backspace in the interactive demo. -* [#246](https://github.com/mgeisler/textwrap/pull/246): Show build - type (debug/release) in interactive demo. -* [#249](https://github.com/mgeisler/textwrap/pull/249): Correctly - compute width while skipping over ANSI escape sequences. - -## Version 0.13.0 (2020-12-05) - -This is a major release which rewrites the core logic, adds many new -features, and fixes a couple of bugs. Most programs which use -`textwrap` stays the same, incompatibilities and upgrade notes are -given below. - -Clone the repository and run the following to explore the new features -in an interactive demo (Linux only): - -```sh -$ cargo run --example interactive --all-features -``` - -### Bug Fixes - -#### Rewritten core wrapping algorithm - -* [#221](https://github.com/mgeisler/textwrap/pull/221): Reformulate - wrapping in terms of words with whitespace and penalties. - -The core wrapping algorithm has been completely rewritten. This fixed -bugs and simplified the code, while also making it possible to use -`textwrap` outside the context of the terminal. - -As part of this, trailing whitespace is now discarded consistently -from wrapped lines. Before we would inconsistently remove whitespace -at the end of wrapped lines, except for the last. Leading whitespace -is still preserved. - -### New Features - -#### Optimal-fit wrapping - -* [#234](https://github.com/mgeisler/textwrap/pull/234): Introduce - wrapping using an optimal-fit algorithm. - -This release adds support for new wrapping algorithm which finds a -globally optimal set of line breaks, taking certain penalties into -account. As an example, the old algorithm would produce - - "To be, or" - "not to be:" - "that is" - "the" - "question" - -Notice how the fourth line with “the” is very short. The new algorithm -shortens the previous lines slightly to produce fewer short lines: - - "To be," - "or not to" - "be: that" - "is the" - "question" - -Use the new `textwrap::core::WrapAlgorithm` enum to select between the -new and old algorithm. By default, the new algorithm is used. - -The optimal-fit algorithm is inspired by the line breaking algorithm -used in TeX, described in the 1981 article [_Breaking Paragraphs into -Lines_](http://www.eprg.org/G53DOC/pdfs/knuth-plass-breaking.pdf) by -Knuth and Plass. - -#### In-place wrapping - -* [#226](https://github.com/mgeisler/textwrap/pull/226): Add a - `fill_inplace` function. - -When the text you want to fill is already a temporary `String`, you -can now mutate it in-place with `fill_inplace`: - -```rust -let mut greeting = format!("Greetings {}, welcome to the game! You have {} lives left.", - player.name, player.lives); -fill_inplace(&mut greeting, line_width); -``` - -This is faster than calling `fill` and it will reuse the memory -already allocated for the string. - -### Changed Features - -#### `Wrapper` is replaced with `Options` - -* [#213](https://github.com/mgeisler/textwrap/pull/213): Simplify API - with only top-level functions. -* [#215](https://github.com/mgeisler/textwrap/pull/215): Reintroducing - the type parameter on `Options` (previously known as `Wrapper`). -* [#219](https://github.com/mgeisler/textwrap/pull/219): Allow using - trait objects with `fill` & `wrap`. -* [#227](https://github.com/mgeisler/textwrap/pull/227): Replace - `WrapOptions` with `Into`. - -The `Wrapper` struct held the options (line width, indentation, etc) -for wrapping text. It was also the entry point for actually wrapping -the text via its methods such as `wrap`, `wrap_iter`, -`into_wrap_iter`, and `fill` methods. - -The struct has been replaced by a simpler `Options` struct which only -holds options. The `Wrapper` methods are gone, their job has been -taken over by the top-level `wrap` and `fill` functions. The signature -of these functions have changed from - -```rust -fn fill(s: &str, width: usize) -> String; - -fn wrap(s: &str, width: usize) -> Vec>; -``` - -to the more general - -```rust -fn fill<'a, S, Opt>(text: &str, options: Opt) -> String -where - S: WordSplitter, - Opt: Into>; - -fn wrap<'a, S, Opt>(text: &str, options: Opt) -> Vec> -where - S: WordSplitter, - Opt: Into>; -``` - -The `Into` bound allows you to pass an `usize` (which -is interpreted as the line width) *and* a full `Options` object. This -allows the new functions to work like the old, plus you can now fully -customize the behavior of the wrapping via `Options` when needed. - -Code that call `textwrap::wrap` or `textwrap::fill` can remain -unchanged. Code that calls into `Wrapper::wrap` or `Wrapper::fill` -will need to be update. This is a mechanical change, please see -[#213](https://github.com/mgeisler/textwrap/pull/213) for examples. - -Thanks to @CryptJar and @Koxiat for their support in the PRs above! - -### Removed Features - -* The `wrap_iter` and `into_wrap_iter` methods are gone. This means - that lazy iteration is no longer supported: you always get all - wrapped lines back as a `Vec`. This was done to simplify the code - and to support the optimal-fit algorithm. - - The first-fit algorithm could still be implemented in an incremental - fashion. Please let us know if this is important to you. - -### Other Changes - -* [#206](https://github.com/mgeisler/textwrap/pull/206): Change - `Wrapper.splitter` from `T: WordSplitter` to `Box`. -* [#216](https://github.com/mgeisler/textwrap/pull/216): Forbid the - use of unsafe code. - -## Version 0.12.1 (2020-07-03) - -This is a bugfix release. - -* Fixed [#176][issue-176]: Mention compile-time wrapping by linking to - the [`textwrap-macros` crate]. -* Fixed [#193][issue-193]: Wrapping with `break_words(false)` was - broken and would cause extra whitespace to be inserted when words - were longer than the line width. - -## Version 0.12.0 (2020-06-26) - -The code has been updated to the [Rust 2018 edition][rust-2018] and -each new release of `textwrap` will only support the latest stable -version of Rust. Trying to support older Rust versions is a fool's -errand: our dependencies keep releasing new patch versions that -require newer and newer versions of Rust. - -The `term_size` feature has been replaced by `terminal_size`. The API -is unchanged, it is just the name of the Cargo feature that changed. - -The `hyphenation` feature now only embeds the hyphenation patterns for -US-English. This slims down the dependency. - -* Fixed [#140][issue-140]: Ignore ANSI escape sequences. -* Fixed [#158][issue-158]: Unintended wrapping when using external splitter. -* Fixed [#177][issue-177]: Update examples to the 2018 edition. - -## Version 0.11.0 (2018-12-09) - -Due to our dependencies bumping their minimum supported version of -Rust, the minimum version of Rust we test against is now 1.22.0. - -* Merged [#141][issue-141]: Fix `dedent` handling of empty lines and - trailing newlines. Thanks @bbqsrc! -* Fixed [#151][issue-151]: Release of version with hyphenation 0.7. - -## Version 0.10.0 (2018-04-28) - -Due to our dependencies bumping their minimum supported version of -Rust, the minimum version of Rust we test against is now 1.17.0. - -* Fixed [#99][issue-99]: Word broken even though it would fit on line. -* Fixed [#107][issue-107]: Automatic hyphenation is off by one. -* Fixed [#122][issue-122]: Take newlines into account when wrapping. -* Fixed [#129][issue-129]: Panic on string with em-dash. - -## Version 0.9.0 (2017-10-05) - -The dependency on `term_size` is now optional, and by default this -feature is not enabled. This is a *breaking change* for users of -`Wrapper::with_termwidth`. Enable the `term_size` feature to restore -the old functionality. - -Added a regression test for the case where `width` is set to -`usize::MAX`, thanks @Fraser999! All public structs now implement -`Debug`, thanks @hcpl! - -* Fixed [#101][issue-101]: Make `term_size` an optional dependency. - -## Version 0.8.0 (2017-09-04) - -The `Wrapper` struct is now generic over the type of word splitter -being used. This means less boxing and a nicer API. The -`Wrapper::word_splitter` method has been removed. This is a *breaking -API change* if you used the method to change the word splitter. - -The `Wrapper` struct has two new methods that will wrap the input text -lazily: `Wrapper::wrap_iter` and `Wrapper::into_wrap_iter`. Use those -if you will be iterating over the wrapped lines one by one. - -* Fixed [#59][issue-59]: `wrap` could return an iterator. Thanks - @hcpl! -* Fixed [#81][issue-81]: Set `html_root_url`. - -## Version 0.7.0 (2017-07-20) - -Version 0.7.0 changes the return type of `Wrapper::wrap` from -`Vec` to `Vec>`. This means that the output lines -borrow data from the input string. This is a *breaking API change* if -you relied on the exact return type of `Wrapper::wrap`. Callers of the -`textwrap::fill` convenience function will see no breakage. - -The above change and other optimizations makes version 0.7.0 roughly -15-30% faster than version 0.6.0. - -The `squeeze_whitespace` option has been removed since it was -complicating the above optimization. Let us know if this option is -important for you so we can provide a work around. - -* Fixed [#58][issue-58]: Add a "fast_wrap" function. -* Fixed [#61][issue-61]: Documentation errors. - -## Version 0.6.0 (2017-05-22) - -Version 0.6.0 adds builder methods to `Wrapper` for easy one-line -initialization and configuration: - -```rust -let wrapper = Wrapper::new(60).break_words(false); -``` - -It also add a new `NoHyphenation` word splitter that will never split -words, not even at existing hyphens. - -* Fixed [#28][issue-28]: Support not squeezing whitespace. - -## Version 0.5.0 (2017-05-15) - -Version 0.5.0 has *breaking API changes*. However, this only affects -code using the hyphenation feature. The feature is now optional, so -you will first need to enable the `hyphenation` feature as described -above. Afterwards, please change your code from -```rust -wrapper.corpus = Some(&corpus); -``` -to -```rust -wrapper.splitter = Box::new(corpus); -``` - -Other changes include optimizations, so version 0.5.0 is roughly -10-15% faster than version 0.4.0. - -* Fixed [#19][issue-19]: Add support for finding terminal size. -* Fixed [#25][issue-25]: Handle words longer than `self.width`. -* Fixed [#26][issue-26]: Support custom indentation. -* Fixed [#36][issue-36]: Support building without `hyphenation`. -* Fixed [#39][issue-39]: Respect non-breaking spaces. - -## Version 0.4.0 (2017-01-24) - -Documented complexities and tested these via `cargo bench`. - -* Fixed [#13][issue-13]: Immediatedly add word if it fits. -* Fixed [#14][issue-14]: Avoid splitting on initial hyphens. - -## Version 0.3.0 (2017-01-07) - -Added support for automatic hyphenation. - -## Version 0.2.0 (2016-12-28) - -Introduced `Wrapper` struct. Added support for wrapping on hyphens. - -## Version 0.1.0 (2016-12-17) - -First public release with support for wrapping strings on whitespace. - -[rust-2018]: https://doc.rust-lang.org/edition-guide/rust-2018/ -[`textwrap-macros` crate]: https://crates.io/crates/textwrap-macros - -[issue-13]: https://github.com/mgeisler/textwrap/issues/13 -[issue-14]: https://github.com/mgeisler/textwrap/issues/14 -[issue-19]: https://github.com/mgeisler/textwrap/issues/19 -[issue-25]: https://github.com/mgeisler/textwrap/issues/25 -[issue-26]: https://github.com/mgeisler/textwrap/issues/26 -[issue-28]: https://github.com/mgeisler/textwrap/issues/28 -[issue-36]: https://github.com/mgeisler/textwrap/issues/36 -[issue-39]: https://github.com/mgeisler/textwrap/issues/39 -[issue-58]: https://github.com/mgeisler/textwrap/issues/58 -[issue-59]: https://github.com/mgeisler/textwrap/issues/59 -[issue-61]: https://github.com/mgeisler/textwrap/issues/61 -[issue-81]: https://github.com/mgeisler/textwrap/issues/81 -[issue-99]: https://github.com/mgeisler/textwrap/issues/99 -[issue-101]: https://github.com/mgeisler/textwrap/issues/101 -[issue-107]: https://github.com/mgeisler/textwrap/issues/107 -[issue-122]: https://github.com/mgeisler/textwrap/issues/122 -[issue-129]: https://github.com/mgeisler/textwrap/issues/129 -[issue-140]: https://github.com/mgeisler/textwrap/issues/140 -[issue-141]: https://github.com/mgeisler/textwrap/issues/141 -[issue-151]: https://github.com/mgeisler/textwrap/issues/151 -[issue-158]: https://github.com/mgeisler/textwrap/issues/158 -[issue-176]: https://github.com/mgeisler/textwrap/issues/176 -[issue-177]: https://github.com/mgeisler/textwrap/issues/177 -[issue-193]: https://github.com/mgeisler/textwrap/issues/193 diff --git a/third_party/rust/textwrap/Cargo.lock b/third_party/rust/textwrap/Cargo.lock deleted file mode 100644 index 98b642073e1c..000000000000 --- a/third_party/rust/textwrap/Cargo.lock +++ /dev/null @@ -1,657 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fst" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "hermit-abi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" - -[[package]] -name = "hyphenation" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf4dd4c44ae85155502a52c48739c8a48185d1449fff1963cffee63c28a50f0" -dependencies = [ - "bincode", - "fst", - "hyphenation_commons", - "pocket-resources", - "serde", -] - -[[package]] -name = "hyphenation_commons" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5febe7a2ade5c7d98eb8b75f946c046b335324b06a14ea0998271504134c05bf" -dependencies = [ - "fst", - "serde", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libredox" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" -dependencies = [ - "bitflags 2.4.2", - "libc", - "redox_syscall", -] - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pocket-resources" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c135f38778ad324d9e9ee68690bac2c1a51f340fdf96ca13e2ab3914eb2e51d8" - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags 2.4.2", - "memchr", - "unicase", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_termios" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" - -[[package]] -name = "regex" -version = "1.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "semver" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" - -[[package]] -name = "serde" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.196" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_spanned" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" -dependencies = [ - "serde", -] - -[[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - -[[package]] -name = "syn" -version = "2.0.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "terminal_size" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" -dependencies = [ - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "termion" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4648c7def6f2043b2568617b9f9b75eae88ca185dbc1f1fda30e95a85d49d7d" -dependencies = [ - "libc", - "libredox", - "numtoa", - "redox_termios", -] - -[[package]] -name = "textwrap" -version = "0.16.1" -dependencies = [ - "hyphenation", - "smawk", - "terminal_size", - "termion", - "unic-emoji-char", - "unicode-linebreak", - "unicode-width", - "version-sync", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-emoji-char" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "version-sync" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835169da0173ea373ddf5987632aac1f918967fbbe58195e304342282efa6089" -dependencies = [ - "proc-macro2", - "pulldown-cmark", - "regex", - "semver", - "syn", - "toml", - "url", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] diff --git a/third_party/rust/textwrap/Cargo.toml b/third_party/rust/textwrap/Cargo.toml deleted file mode 100644 index 1493f0a8a985..000000000000 --- a/third_party/rust/textwrap/Cargo.toml +++ /dev/null @@ -1,91 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.56" -name = "textwrap" -version = "0.16.1" -authors = ["Martin Geisler "] -exclude = [ - ".github/", - ".gitignore", - "benchmarks/", - "examples/", - "fuzz/", - "images/", -] -description = "Library for word wrapping, indenting, and dedenting strings. Has optional support for Unicode and emojis as well as machine hyphenation." -documentation = "https://docs.rs/textwrap/" -readme = "README.md" -keywords = [ - "text", - "formatting", - "wrap", - "typesetting", - "hyphenation", -] -categories = [ - "text-processing", - "command-line-interface", -] -license = "MIT" -repository = "https://github.com/mgeisler/textwrap" - -[package.metadata.docs.rs] -all-features = true - -[[example]] -name = "hyphenation" -path = "examples/hyphenation.rs" -required-features = ["hyphenation"] - -[[example]] -name = "termwidth" -path = "examples/termwidth.rs" -required-features = ["terminal_size"] - -[dependencies.hyphenation] -version = "0.8.4" -features = ["embed_en-us"] -optional = true - -[dependencies.smawk] -version = "0.3.1" -optional = true - -[dependencies.terminal_size] -version = "0.2.1" -optional = true - -[dependencies.unicode-linebreak] -version = "0.1.4" -optional = true - -[dependencies.unicode-width] -version = "0.1.10" -optional = true - -[dev-dependencies.unic-emoji-char] -version = "0.9.0" - -[dev-dependencies.version-sync] -version = "0.9.4" - -[features] -default = [ - "unicode-linebreak", - "unicode-width", - "smawk", -] - -[target."cfg(unix)".dev-dependencies.termion] -version = "2.0.1" diff --git a/third_party/rust/textwrap/LICENSE b/third_party/rust/textwrap/LICENSE deleted file mode 100644 index 0d37ec3891d8..000000000000 --- a/third_party/rust/textwrap/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016 Martin Geisler - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/third_party/rust/textwrap/README.md b/third_party/rust/textwrap/README.md deleted file mode 100644 index bf13cd0957c8..000000000000 --- a/third_party/rust/textwrap/README.md +++ /dev/null @@ -1,176 +0,0 @@ -# Textwrap - -[![](https://github.com/mgeisler/textwrap/workflows/build/badge.svg)][build-status] -[![](https://codecov.io/gh/mgeisler/textwrap/branch/master/graph/badge.svg)][codecov] -[![](https://img.shields.io/crates/v/textwrap.svg)][crates-io] -[![](https://docs.rs/textwrap/badge.svg)][api-docs] - -Textwrap is a library for wrapping and indenting text. It is most -often used by command-line programs to format dynamic output nicely so -it looks good in a terminal. You can also use Textwrap to wrap text -set in a proportional font—such as text used to generate PDF files, or -drawn on a [HTML5 canvas using WebAssembly][wasm-demo]. - -## Usage - -To use the textwrap crate, add this to your `Cargo.toml` file: -```toml -[dependencies] -textwrap = "0.16" -``` - -By default, this enables word wrapping with support for Unicode -strings. Extra features can be enabled with Cargo features—and the -Unicode support can be disabled if needed. This allows you slim down -the library and so you will only pay for the features you actually -use. - -Please see the [_Cargo Features_ in the crate -documentation](https://docs.rs/textwrap/#cargo-features) for a full -list of the available features as well as their impact on the size of -your binary. - -## Documentation - -**[API documentation][api-docs]** - -## Getting Started - -Word wrapping is easy using the `wrap` and `fill` functions: - -```rust -#[cfg(feature = "smawk")] { -let text = "textwrap: an efficient and powerful library for wrapping text."; -assert_eq!( - textwrap::wrap(text, 28), - vec![ - "textwrap: an efficient", - "and powerful library for", - "wrapping text.", - ] -); -} -``` - -Sharp-eyed readers will notice that the first line is 22 columns wide. -So why is the word “and” put in the second line when there is space -for it in the first line? - -The explanation is that textwrap does not just wrap text one line at a -time. Instead, it uses an optimal-fit algorithm which looks ahead and -chooses line breaks which minimize the gaps left at ends of lines. -This is controlled with the `smawk` Cargo feature, which is why the -example is wrapped in the `cfg`-block. - -Without look-ahead, the first line would be longer and the text would -look like this: - -```rust -#[cfg(not(feature = "smawk"))] { -let text = "textwrap: an efficient and powerful library for wrapping text."; -assert_eq!( - textwrap::wrap(text, 28), - vec![ - "textwrap: an efficient and", - "powerful library for", - "wrapping text.", - ] -); -} -``` - -The second line is now shorter and the text is more ragged. The kind -of wrapping can be configured via `Options::wrap_algorithm`. - -If you enable the `hyphenation` Cargo feature, you get support for -automatic hyphenation for [about 70 languages][patterns] via -high-quality TeX hyphenation patterns. - -Your program must load the hyphenation pattern and configure -`Options::word_splitter` to use it: - -```rust -#[cfg(feature = "hyphenation")] { -use hyphenation::{Language, Load, Standard}; -use textwrap::{fill, Options, WordSplitter}; - -let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); -let options = textwrap::Options::new(28).word_splitter(WordSplitter::Hyphenation(dictionary)); -let text = "textwrap: an efficient and powerful library for wrapping text."; - -assert_eq!( - textwrap::wrap(text, &options), - vec![ - "textwrap: an efficient and", - "powerful library for wrap-", - "ping text." - ] -); -} -``` - -The US-English hyphenation patterns are embedded when you enable the -`hyphenation` feature. They are licensed under a [permissive -license][en-us license] and take up about 88 KB in your binary. If you -need hyphenation for other languages, you need to download a -[precompiled `.bincode` file][bincode] and load it yourself. Please -see the [`hyphenation` documentation] for details. - -## Wrapping Strings at Compile Time - -If your strings are known at compile time, please take a look at the -procedural macros from the [`textwrap-macros` crate]. - -## Examples - -The library comes with [a -collection](https://github.com/mgeisler/textwrap/tree/master/examples) -of small example programs that shows various features. - -If you want to see Textwrap in action right away, then take a look at -[`examples/wasm/`], which shows how to wrap sans-serif, serif, and -monospace text. It uses WebAssembly and is automatically deployed to -https://mgeisler.github.io/textwrap/. - -For the command-line examples, you’re invited to clone the repository -and try them out for yourself! Of special note is -[`examples/interactive.rs`]. This is a demo program which demonstrates -most of the available features: you can enter text and adjust the -width at which it is wrapped interactively. You can also adjust the -`Options` used to see the effect of different `WordSplitter`s and wrap -algorithms. - -Run the demo with - -```sh -$ cargo run --example interactive -``` - -The demo needs a Linux terminal to function. - -## Release History - -Please see the [CHANGELOG file] for details on the changes made in -each release. - -## License - -Textwrap can be distributed according to the [MIT license][mit]. -Contributions will be accepted under the same license. - -[crates-io]: https://crates.io/crates/textwrap -[build-status]: https://github.com/mgeisler/textwrap/actions?query=workflow%3Abuild+branch%3Amaster -[codecov]: https://codecov.io/gh/mgeisler/textwrap -[wasm-demo]: https://mgeisler.github.io/textwrap/ -[`textwrap-macros` crate]: https://crates.io/crates/textwrap-macros -[`hyphenation` example]: https://github.com/mgeisler/textwrap/blob/master/examples/hyphenation.rs -[`termwidth` example]: https://github.com/mgeisler/textwrap/blob/master/examples/termwidth.rs -[patterns]: https://github.com/tapeinosyne/hyphenation/tree/master/patterns -[en-us license]: https://github.com/hyphenation/tex-hyphen/blob/master/hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-en-us.tex -[bincode]: https://github.com/tapeinosyne/hyphenation/tree/master/dictionaries -[`hyphenation` documentation]: http://docs.rs/hyphenation -[`examples/wasm/`]: https://github.com/mgeisler/textwrap/tree/master/examples/wasm -[`examples/interactive.rs`]: https://github.com/mgeisler/textwrap/tree/master/examples/interactive.rs -[api-docs]: https://docs.rs/textwrap/ -[CHANGELOG file]: https://github.com/mgeisler/textwrap/blob/master/CHANGELOG.md -[mit]: LICENSE diff --git a/third_party/rust/textwrap/rustfmt.toml b/third_party/rust/textwrap/rustfmt.toml deleted file mode 100644 index c1578aafbcf2..000000000000 --- a/third_party/rust/textwrap/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -imports_granularity = "Module" diff --git a/third_party/rust/textwrap/src/columns.rs b/third_party/rust/textwrap/src/columns.rs deleted file mode 100644 index d14d5588fa26..000000000000 --- a/third_party/rust/textwrap/src/columns.rs +++ /dev/null @@ -1,193 +0,0 @@ -//! Functionality for wrapping text into columns. - -use crate::core::display_width; -use crate::{wrap, Options}; - -/// Wrap text into columns with a given total width. -/// -/// The `left_gap`, `middle_gap` and `right_gap` arguments specify the -/// strings to insert before, between, and after the columns. The -/// total width of all columns and all gaps is specified using the -/// `total_width_or_options` argument. This argument can simply be an -/// integer if you want to use default settings when wrapping, or it -/// can be a [`Options`] value if you want to customize the wrapping. -/// -/// If the columns are narrow, it is recommended to set -/// [`Options::break_words`] to `true` to prevent words from -/// protruding into the margins. -/// -/// The per-column width is computed like this: -/// -/// ``` -/// # let (left_gap, middle_gap, right_gap) = ("", "", ""); -/// # let columns = 2; -/// # let options = textwrap::Options::new(80); -/// let inner_width = options.width -/// - textwrap::core::display_width(left_gap) -/// - textwrap::core::display_width(right_gap) -/// - textwrap::core::display_width(middle_gap) * (columns - 1); -/// let column_width = inner_width / columns; -/// ``` -/// -/// The `text` is wrapped using [`wrap()`] and the given `options` -/// argument, but the width is overwritten to the computed -/// `column_width`. -/// -/// # Panics -/// -/// Panics if `columns` is zero. -/// -/// # Examples -/// -/// ``` -/// use textwrap::wrap_columns; -/// -/// let text = "\ -/// This is an example text, which is wrapped into three columns. \ -/// Notice how the final column can be shorter than the others."; -/// -/// #[cfg(feature = "smawk")] -/// assert_eq!(wrap_columns(text, 3, 50, "| ", " | ", " |"), -/// vec!["| This is | into three | column can be |", -/// "| an example | columns. | shorter than |", -/// "| text, which | Notice how | the others. |", -/// "| is wrapped | the final | |"]); -/// -/// // Without the `smawk` feature, the middle column is a little more uneven: -/// #[cfg(not(feature = "smawk"))] -/// assert_eq!(wrap_columns(text, 3, 50, "| ", " | ", " |"), -/// vec!["| This is an | three | column can be |", -/// "| example text, | columns. | shorter than |", -/// "| which is | Notice how | the others. |", -/// "| wrapped into | the final | |"]); -pub fn wrap_columns<'a, Opt>( - text: &str, - columns: usize, - total_width_or_options: Opt, - left_gap: &str, - middle_gap: &str, - right_gap: &str, -) -> Vec -where - Opt: Into>, -{ - assert!(columns > 0); - - let mut options: Options = total_width_or_options.into(); - - let inner_width = options - .width - .saturating_sub(display_width(left_gap)) - .saturating_sub(display_width(right_gap)) - .saturating_sub(display_width(middle_gap) * (columns - 1)); - - let column_width = std::cmp::max(inner_width / columns, 1); - options.width = column_width; - let last_column_padding = " ".repeat(inner_width % column_width); - let wrapped_lines = wrap(text, options); - let lines_per_column = - wrapped_lines.len() / columns + usize::from(wrapped_lines.len() % columns > 0); - let mut lines = Vec::new(); - for line_no in 0..lines_per_column { - let mut line = String::from(left_gap); - for column_no in 0..columns { - match wrapped_lines.get(line_no + column_no * lines_per_column) { - Some(column_line) => { - line.push_str(column_line); - line.push_str(&" ".repeat(column_width - display_width(column_line))); - } - None => { - line.push_str(&" ".repeat(column_width)); - } - } - if column_no == columns - 1 { - line.push_str(&last_column_padding); - } else { - line.push_str(middle_gap); - } - } - line.push_str(right_gap); - lines.push(line); - } - - lines -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn wrap_columns_empty_text() { - assert_eq!(wrap_columns("", 1, 10, "| ", "", " |"), vec!["| |"]); - } - - #[test] - fn wrap_columns_single_column() { - assert_eq!( - wrap_columns("Foo", 3, 30, "| ", " | ", " |"), - vec!["| Foo | | |"] - ); - } - - #[test] - fn wrap_columns_uneven_columns() { - // The gaps take up a total of 5 columns, so the columns are - // (21 - 5)/4 = 4 columns wide: - assert_eq!( - wrap_columns("Foo Bar Baz Quux", 4, 21, "|", "|", "|"), - vec!["|Foo |Bar |Baz |Quux|"] - ); - // As the total width increases, the last column absorbs the - // excess width: - assert_eq!( - wrap_columns("Foo Bar Baz Quux", 4, 24, "|", "|", "|"), - vec!["|Foo |Bar |Baz |Quux |"] - ); - // Finally, when the width is 25, the columns can be resized - // to a width of (25 - 5)/4 = 5 columns: - assert_eq!( - wrap_columns("Foo Bar Baz Quux", 4, 25, "|", "|", "|"), - vec!["|Foo |Bar |Baz |Quux |"] - ); - } - - #[test] - #[cfg(feature = "unicode-width")] - fn wrap_columns_with_emojis() { - assert_eq!( - wrap_columns( - "Words and a few emojis 😍 wrapped in ⓶ columns", - 2, - 30, - "✨ ", - " ⚽ ", - " 👀" - ), - vec![ - "✨ Words ⚽ wrapped in 👀", - "✨ and a few ⚽ ⓶ columns 👀", - "✨ emojis 😍 ⚽ 👀" - ] - ); - } - - #[test] - fn wrap_columns_big_gaps() { - // The column width shrinks to 1 because the gaps take up all - // the space. - assert_eq!( - wrap_columns("xyz", 2, 10, "----> ", " !!! ", " <----"), - vec![ - "----> x !!! z <----", // - "----> y !!! <----" - ] - ); - } - - #[test] - #[should_panic] - fn wrap_columns_panic_with_zero_columns() { - wrap_columns("", 0, 10, "", "", ""); - } -} diff --git a/third_party/rust/textwrap/src/core.rs b/third_party/rust/textwrap/src/core.rs deleted file mode 100644 index 6b07f763c8a2..000000000000 --- a/third_party/rust/textwrap/src/core.rs +++ /dev/null @@ -1,461 +0,0 @@ -//! Building blocks for advanced wrapping functionality. -//! -//! The functions and structs in this module can be used to implement -//! advanced wrapping functionality when [`wrap()`](crate::wrap()) -//! [`fill()`](crate::fill()) don't do what you want. -//! -//! In general, you want to follow these steps when wrapping -//! something: -//! -//! 1. Split your input into [`Fragment`]s. These are abstract blocks -//! of text or content which can be wrapped into lines. See -//! [`WordSeparator`](crate::word_separators::WordSeparator) for -//! how to do this for text. -//! -//! 2. Potentially split your fragments into smaller pieces. This -//! allows you to implement things like hyphenation. If you use the -//! `Word` type, you can use [`WordSplitter`](crate::WordSplitter) -//! enum for this. -//! -//! 3. Potentially break apart fragments that are still too large to -//! fit on a single line. This is implemented in [`break_words`]. -//! -//! 4. Finally take your fragments and put them into lines. There are -//! two algorithms for this in the -//! [`wrap_algorithms`](crate::wrap_algorithms) module: -//! [`wrap_optimal_fit`](crate::wrap_algorithms::wrap_optimal_fit) -//! and [`wrap_first_fit`](crate::wrap_algorithms::wrap_first_fit). -//! The former produces better line breaks, the latter is faster. -//! -//! 5. Iterate through the slices returned by the wrapping functions -//! and construct your lines of output. -//! -//! Please [open an issue](https://github.com/mgeisler/textwrap/) if -//! the functionality here is not sufficient or if you have ideas for -//! improving it. We would love to hear from you! - -/// The CSI or “Control Sequence Introducer” introduces an ANSI escape -/// sequence. This is typically used for colored text and will be -/// ignored when computing the text width. -const CSI: (char, char) = ('\x1b', '['); -/// The final bytes of an ANSI escape sequence must be in this range. -const ANSI_FINAL_BYTE: std::ops::RangeInclusive = '\x40'..='\x7e'; - -/// Skip ANSI escape sequences. -/// -/// The `ch` is the current `char`, the `chars` provide the following -/// characters. The `chars` will be modified if `ch` is the start of -/// an ANSI escape sequence. -/// -/// Returns `true` if one or more chars were skipped. -#[inline] -pub(crate) fn skip_ansi_escape_sequence>(ch: char, chars: &mut I) -> bool { - if ch != CSI.0 { - return false; // Nothing to skip here. - } - - let next = chars.next(); - if next == Some(CSI.1) { - // We have found the start of an ANSI escape code, typically - // used for colored terminal text. We skip until we find a - // "final byte" in the range 0x40–0x7E. - for ch in chars { - if ANSI_FINAL_BYTE.contains(&ch) { - break; - } - } - } else if next == Some(']') { - // We have found the start of an Operating System Command, - // which extends until the next sequence "\x1b\\" (the String - // Terminator sequence) or the BEL character. The BEL - // character is non-standard, but it is still used quite - // often, for example, by GNU ls. - let mut last = ']'; - for new in chars { - if new == '\x07' || (new == '\\' && last == CSI.0) { - break; - } - last = new; - } - } - - true // Indicate that some chars were skipped. -} - -#[cfg(feature = "unicode-width")] -#[inline] -fn ch_width(ch: char) -> usize { - unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) -} - -/// First character which [`ch_width`] will classify as double-width. -/// Please see [`display_width`]. -#[cfg(not(feature = "unicode-width"))] -const DOUBLE_WIDTH_CUTOFF: char = '\u{1100}'; - -#[cfg(not(feature = "unicode-width"))] -#[inline] -fn ch_width(ch: char) -> usize { - if ch < DOUBLE_WIDTH_CUTOFF { - 1 - } else { - 2 - } -} - -/// Compute the display width of `text` while skipping over ANSI -/// escape sequences. -/// -/// # Examples -/// -/// ``` -/// use textwrap::core::display_width; -/// -/// assert_eq!(display_width("Café Plain"), 10); -/// assert_eq!(display_width("\u{1b}[31mCafé Rouge\u{1b}[0m"), 10); -/// assert_eq!(display_width("\x1b]8;;http://example.com\x1b\\This is a link\x1b]8;;\x1b\\"), 14); -/// ``` -/// -/// **Note:** When the `unicode-width` Cargo feature is disabled, the -/// width of a `char` is determined by a crude approximation which -/// simply counts chars below U+1100 as 1 column wide, and all other -/// characters as 2 columns wide. With the feature enabled, function -/// will correctly deal with [combining characters] in their -/// decomposed form (see [Unicode equivalence]). -/// -/// An example of a decomposed character is “é”, which can be -/// decomposed into: “e” followed by a combining acute accent: “◌́”. -/// Without the `unicode-width` Cargo feature, every `char` below -/// U+1100 has a width of 1. This includes the combining accent: -/// -/// ``` -/// use textwrap::core::display_width; -/// -/// assert_eq!(display_width("Cafe Plain"), 10); -/// #[cfg(feature = "unicode-width")] -/// assert_eq!(display_width("Cafe\u{301} Plain"), 10); -/// #[cfg(not(feature = "unicode-width"))] -/// assert_eq!(display_width("Cafe\u{301} Plain"), 11); -/// ``` -/// -/// ## Emojis and CJK Characters -/// -/// Characters such as emojis and [CJK characters] used in the -/// Chinese, Japanese, and Korean languages are seen as double-width, -/// even if the `unicode-width` feature is disabled: -/// -/// ``` -/// use textwrap::core::display_width; -/// -/// assert_eq!(display_width("😂😭🥺🤣✨😍🙏🥰😊🔥"), 20); -/// assert_eq!(display_width("你好"), 4); // “Nǐ hǎo” or “Hello” in Chinese -/// ``` -/// -/// # Limitations -/// -/// The displayed width of a string cannot always be computed from the -/// string alone. This is because the width depends on the rendering -/// engine used. This is particularly visible with [emoji modifier -/// sequences] where a base emoji is modified with, e.g., skin tone or -/// hair color modifiers. It is up to the rendering engine to detect -/// this and to produce a suitable emoji. -/// -/// A simple example is “❤️”, which consists of “❤” (U+2764: Black -/// Heart Symbol) followed by U+FE0F (Variation Selector-16). By -/// itself, “❤” is a black heart, but if you follow it with the -/// variant selector, you may get a wider red heart. -/// -/// A more complex example would be “👨‍🦰” which should depict a man -/// with red hair. Here the computed width is too large — and the -/// width differs depending on the use of the `unicode-width` feature: -/// -/// ``` -/// use textwrap::core::display_width; -/// -/// assert_eq!("👨‍🦰".chars().collect::>(), ['\u{1f468}', '\u{200d}', '\u{1f9b0}']); -/// #[cfg(feature = "unicode-width")] -/// assert_eq!(display_width("👨‍🦰"), 4); -/// #[cfg(not(feature = "unicode-width"))] -/// assert_eq!(display_width("👨‍🦰"), 6); -/// ``` -/// -/// This happens because the grapheme consists of three code points: -/// “👨” (U+1F468: Man), Zero Width Joiner (U+200D), and “🦰” -/// (U+1F9B0: Red Hair). You can see them above in the test. With -/// `unicode-width` enabled, the ZWJ is correctly seen as having zero -/// width, without it is counted as a double-width character. -/// -/// ## Terminal Support -/// -/// Modern browsers typically do a great job at combining characters -/// as shown above, but terminals often struggle more. As an example, -/// Gnome Terminal version 3.38.1, shows “❤️” as a big red heart, but -/// shows "👨‍🦰" as “👨🦰”. -/// -/// [combining characters]: https://en.wikipedia.org/wiki/Combining_character -/// [Unicode equivalence]: https://en.wikipedia.org/wiki/Unicode_equivalence -/// [CJK characters]: https://en.wikipedia.org/wiki/CJK_characters -/// [emoji modifier sequences]: https://unicode.org/emoji/charts/full-emoji-modifiers.html -pub fn display_width(text: &str) -> usize { - let mut chars = text.chars(); - let mut width = 0; - while let Some(ch) = chars.next() { - if skip_ansi_escape_sequence(ch, &mut chars) { - continue; - } - width += ch_width(ch); - } - width -} - -/// A (text) fragment denotes the unit which we wrap into lines. -/// -/// Fragments represent an abstract _word_ plus the _whitespace_ -/// following the word. In case the word falls at the end of the line, -/// the whitespace is dropped and a so-called _penalty_ is inserted -/// instead (typically `"-"` if the word was hyphenated). -/// -/// For wrapping purposes, the precise content of the word, the -/// whitespace, and the penalty is irrelevant. All we need to know is -/// the displayed width of each part, which this trait provides. -pub trait Fragment: std::fmt::Debug { - /// Displayed width of word represented by this fragment. - fn width(&self) -> f64; - - /// Displayed width of the whitespace that must follow the word - /// when the word is not at the end of a line. - fn whitespace_width(&self) -> f64; - - /// Displayed width of the penalty that must be inserted if the - /// word falls at the end of a line. - fn penalty_width(&self) -> f64; -} - -/// A piece of wrappable text, including any trailing whitespace. -/// -/// A `Word` is an example of a [`Fragment`], so it has a width, -/// trailing whitespace, and potentially a penalty item. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct Word<'a> { - /// Word content. - pub word: &'a str, - /// Whitespace to insert if the word does not fall at the end of a line. - pub whitespace: &'a str, - /// Penalty string to insert if the word falls at the end of a line. - pub penalty: &'a str, - // Cached width in columns. - pub(crate) width: usize, -} - -impl std::ops::Deref for Word<'_> { - type Target = str; - - fn deref(&self) -> &Self::Target { - self.word - } -} - -impl<'a> Word<'a> { - /// Construct a `Word` from a string. - /// - /// A trailing stretch of `' '` is automatically taken to be the - /// whitespace part of the word. - pub fn from(word: &str) -> Word<'_> { - let trimmed = word.trim_end_matches(' '); - Word { - word: trimmed, - width: display_width(trimmed), - whitespace: &word[trimmed.len()..], - penalty: "", - } - } - - /// Break this word into smaller words with a width of at most - /// `line_width`. The whitespace and penalty from this `Word` is - /// added to the last piece. - /// - /// # Examples - /// - /// ``` - /// use textwrap::core::Word; - /// assert_eq!( - /// Word::from("Hello! ").break_apart(3).collect::>(), - /// vec![Word::from("Hel"), Word::from("lo! ")] - /// ); - /// ``` - pub fn break_apart<'b>(&'b self, line_width: usize) -> impl Iterator> + 'b { - let mut char_indices = self.word.char_indices(); - let mut offset = 0; - let mut width = 0; - - std::iter::from_fn(move || { - while let Some((idx, ch)) = char_indices.next() { - if skip_ansi_escape_sequence(ch, &mut char_indices.by_ref().map(|(_, ch)| ch)) { - continue; - } - - if width > 0 && width + ch_width(ch) > line_width { - let word = Word { - word: &self.word[offset..idx], - width: width, - whitespace: "", - penalty: "", - }; - offset = idx; - width = ch_width(ch); - return Some(word); - } - - width += ch_width(ch); - } - - if offset < self.word.len() { - let word = Word { - word: &self.word[offset..], - width: width, - whitespace: self.whitespace, - penalty: self.penalty, - }; - offset = self.word.len(); - return Some(word); - } - - None - }) - } -} - -impl Fragment for Word<'_> { - #[inline] - fn width(&self) -> f64 { - self.width as f64 - } - - // We assume the whitespace consist of ' ' only. This allows us to - // compute the display width in constant time. - #[inline] - fn whitespace_width(&self) -> f64 { - self.whitespace.len() as f64 - } - - // We assume the penalty is `""` or `"-"`. This allows us to - // compute the display width in constant time. - #[inline] - fn penalty_width(&self) -> f64 { - self.penalty.len() as f64 - } -} - -/// Forcibly break words wider than `line_width` into smaller words. -/// -/// This simply calls [`Word::break_apart`] on words that are too -/// wide. This means that no extra `'-'` is inserted, the word is -/// simply broken into smaller pieces. -pub fn break_words<'a, I>(words: I, line_width: usize) -> Vec> -where - I: IntoIterator>, -{ - let mut shortened_words = Vec::new(); - for word in words { - if word.width() > line_width as f64 { - shortened_words.extend(word.break_apart(line_width)); - } else { - shortened_words.push(word); - } - } - shortened_words -} - -#[cfg(test)] -mod tests { - use super::*; - - #[cfg(feature = "unicode-width")] - use unicode_width::UnicodeWidthChar; - - #[test] - fn skip_ansi_escape_sequence_works() { - let blue_text = "\u{1b}[34mHello\u{1b}[0m"; - let mut chars = blue_text.chars(); - let ch = chars.next().unwrap(); - assert!(skip_ansi_escape_sequence(ch, &mut chars)); - assert_eq!(chars.next(), Some('H')); - } - - #[test] - fn emojis_have_correct_width() { - use unic_emoji_char::is_emoji; - - // Emojis in the Basic Latin (ASCII) and Latin-1 Supplement - // blocks all have a width of 1 column. This includes - // characters such as '#' and '©'. - for ch in '\u{1}'..'\u{FF}' { - if is_emoji(ch) { - let desc = format!("{:?} U+{:04X}", ch, ch as u32); - - #[cfg(feature = "unicode-width")] - assert_eq!(ch.width().unwrap(), 1, "char: {}", desc); - - #[cfg(not(feature = "unicode-width"))] - assert_eq!(ch_width(ch), 1, "char: {}", desc); - } - } - - // Emojis in the remaining blocks of the Basic Multilingual - // Plane (BMP), in the Supplementary Multilingual Plane (SMP), - // and in the Supplementary Ideographic Plane (SIP), are all 1 - // or 2 columns wide when unicode-width is used, and always 2 - // columns wide otherwise. This includes all of our favorite - // emojis such as 😊. - for ch in '\u{FF}'..'\u{2FFFF}' { - if is_emoji(ch) { - let desc = format!("{:?} U+{:04X}", ch, ch as u32); - - #[cfg(feature = "unicode-width")] - assert!(ch.width().unwrap() <= 2, "char: {}", desc); - - #[cfg(not(feature = "unicode-width"))] - assert_eq!(ch_width(ch), 2, "char: {}", desc); - } - } - - // The remaining planes contain almost no assigned code points - // and thus also no emojis. - } - - #[test] - fn display_width_works() { - assert_eq!("Café Plain".len(), 11); // “é” is two bytes - assert_eq!(display_width("Café Plain"), 10); - assert_eq!(display_width("\u{1b}[31mCafé Rouge\u{1b}[0m"), 10); - assert_eq!( - display_width("\x1b]8;;http://example.com\x1b\\This is a link\x1b]8;;\x1b\\"), - 14 - ); - } - - #[test] - fn display_width_narrow_emojis() { - #[cfg(feature = "unicode-width")] - assert_eq!(display_width("⁉"), 1); - - // The ⁉ character is above DOUBLE_WIDTH_CUTOFF. - #[cfg(not(feature = "unicode-width"))] - assert_eq!(display_width("⁉"), 2); - } - - #[test] - fn display_width_narrow_emojis_variant_selector() { - #[cfg(feature = "unicode-width")] - assert_eq!(display_width("⁉\u{fe0f}"), 1); - - // The variant selector-16 is also counted. - #[cfg(not(feature = "unicode-width"))] - assert_eq!(display_width("⁉\u{fe0f}"), 4); - } - - #[test] - fn display_width_emojis() { - assert_eq!(display_width("😂😭🥺🤣✨😍🙏🥰😊🔥"), 20); - } -} diff --git a/third_party/rust/textwrap/src/fill.rs b/third_party/rust/textwrap/src/fill.rs deleted file mode 100644 index fbcaab9e210b..000000000000 --- a/third_party/rust/textwrap/src/fill.rs +++ /dev/null @@ -1,298 +0,0 @@ -//! Functions for filling text. - -use crate::{wrap, wrap_algorithms, Options, WordSeparator}; - -/// Fill a line of text at a given width. -/// -/// The result is a [`String`], complete with newlines between each -/// line. Use [`wrap()`] if you need access to the individual lines. -/// -/// The easiest way to use this function is to pass an integer for -/// `width_or_options`: -/// -/// ``` -/// use textwrap::fill; -/// -/// assert_eq!( -/// fill("Memory safety without garbage collection.", 15), -/// "Memory safety\nwithout garbage\ncollection." -/// ); -/// ``` -/// -/// If you need to customize the wrapping, you can pass an [`Options`] -/// instead of an `usize`: -/// -/// ``` -/// use textwrap::{fill, Options}; -/// -/// let options = Options::new(15) -/// .initial_indent("- ") -/// .subsequent_indent(" "); -/// assert_eq!( -/// fill("Memory safety without garbage collection.", &options), -/// "- Memory safety\n without\n garbage\n collection." -/// ); -/// ``` -pub fn fill<'a, Opt>(text: &str, width_or_options: Opt) -> String -where - Opt: Into>, -{ - let options = width_or_options.into(); - - if text.len() < options.width && !text.contains('\n') && options.initial_indent.is_empty() { - String::from(text.trim_end_matches(' ')) - } else { - fill_slow_path(text, options) - } -} - -/// Slow path for fill. -/// -/// This is taken when `text` is longer than `options.width`. -pub(crate) fn fill_slow_path(text: &str, options: Options<'_>) -> String { - // This will avoid reallocation in simple cases (no - // indentation, no hyphenation). - let mut result = String::with_capacity(text.len()); - - let line_ending_str = options.line_ending.as_str(); - for (i, line) in wrap(text, options).iter().enumerate() { - if i > 0 { - result.push_str(line_ending_str); - } - result.push_str(line); - } - - result -} - -/// Fill `text` in-place without reallocating the input string. -/// -/// This function works by modifying the input string: some `' '` -/// characters will be replaced by `'\n'` characters. The rest of the -/// text remains untouched. -/// -/// Since we can only replace existing whitespace in the input with -/// `'\n'` (there is no space for `"\r\n"`), we cannot do hyphenation -/// nor can we split words longer than the line width. We also need to -/// use `AsciiSpace` as the word separator since we need `' '` -/// characters between words in order to replace some of them with a -/// `'\n'`. Indentation is also ruled out. In other words, -/// `fill_inplace(width)` behaves as if you had called [`fill()`] with -/// these options: -/// -/// ``` -/// # use textwrap::{core, LineEnding, Options, WordSplitter, WordSeparator, WrapAlgorithm}; -/// # let width = 80; -/// Options::new(width) -/// .break_words(false) -/// .line_ending(LineEnding::LF) -/// .word_separator(WordSeparator::AsciiSpace) -/// .wrap_algorithm(WrapAlgorithm::FirstFit) -/// .word_splitter(WordSplitter::NoHyphenation); -/// ``` -/// -/// The wrap algorithm is -/// [`WrapAlgorithm::FirstFit`](crate::WrapAlgorithm::FirstFit) since -/// this is the fastest algorithm — and the main reason to use -/// `fill_inplace` is to get the string broken into newlines as fast -/// as possible. -/// -/// A last difference is that (unlike [`fill()`]) `fill_inplace` can -/// leave trailing whitespace on lines. This is because we wrap by -/// inserting a `'\n'` at the final whitespace in the input string: -/// -/// ``` -/// let mut text = String::from("Hello World!"); -/// textwrap::fill_inplace(&mut text, 10); -/// assert_eq!(text, "Hello \nWorld!"); -/// ``` -/// -/// If we didn't do this, the word `World!` would end up being -/// indented. You can avoid this if you make sure that your input text -/// has no double spaces. -/// -/// # Performance -/// -/// In benchmarks, `fill_inplace` is about twice as fast as -/// [`fill()`]. Please see the [`linear` -/// benchmark](https://github.com/mgeisler/textwrap/blob/master/benchmarks/linear.rs) -/// for details. -pub fn fill_inplace(text: &mut String, width: usize) { - let mut indices = Vec::new(); - - let mut offset = 0; - for line in text.split('\n') { - let words = WordSeparator::AsciiSpace - .find_words(line) - .collect::>(); - let wrapped_words = wrap_algorithms::wrap_first_fit(&words, &[width as f64]); - - let mut line_offset = offset; - for words in &wrapped_words[..wrapped_words.len() - 1] { - let line_len = words - .iter() - .map(|word| word.len() + word.whitespace.len()) - .sum::(); - - line_offset += line_len; - // We've advanced past all ' ' characters -- want to move - // one ' ' backwards and insert our '\n' there. - indices.push(line_offset - 1); - } - - // Advance past entire line, plus the '\n' which was removed - // by the split call above. - offset += line.len() + 1; - } - - let mut bytes = std::mem::take(text).into_bytes(); - for idx in indices { - bytes[idx] = b'\n'; - } - *text = String::from_utf8(bytes).unwrap(); -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::WrapAlgorithm; - - #[test] - fn fill_simple() { - assert_eq!(fill("foo bar baz", 10), "foo bar\nbaz"); - } - - #[test] - fn fill_unicode_boundary() { - // https://github.com/mgeisler/textwrap/issues/390 - fill("\u{1b}!Ͽ", 10); - } - - #[test] - fn non_breaking_space() { - let options = Options::new(5).break_words(false); - assert_eq!(fill("foo bar baz", &options), "foo bar baz"); - } - - #[test] - fn non_breaking_hyphen() { - let options = Options::new(5).break_words(false); - assert_eq!(fill("foo‑bar‑baz", &options), "foo‑bar‑baz"); - } - - #[test] - fn fill_preserves_line_breaks_trims_whitespace() { - assert_eq!(fill(" ", 80), ""); - assert_eq!(fill(" \n ", 80), "\n"); - assert_eq!(fill(" \n \n \n ", 80), "\n\n\n"); - } - - #[test] - fn preserve_line_breaks() { - assert_eq!(fill("", 80), ""); - assert_eq!(fill("\n", 80), "\n"); - assert_eq!(fill("\n\n\n", 80), "\n\n\n"); - assert_eq!(fill("test\n", 80), "test\n"); - assert_eq!(fill("test\n\na\n\n", 80), "test\n\na\n\n"); - assert_eq!( - fill( - "1 3 5 7\n1 3 5 7", - Options::new(7).wrap_algorithm(WrapAlgorithm::FirstFit) - ), - "1 3 5 7\n1 3 5 7" - ); - assert_eq!( - fill( - "1 3 5 7\n1 3 5 7", - Options::new(5).wrap_algorithm(WrapAlgorithm::FirstFit) - ), - "1 3 5\n7\n1 3 5\n7" - ); - } - - #[test] - fn break_words_line_breaks() { - assert_eq!(fill("ab\ncdefghijkl", 5), "ab\ncdefg\nhijkl"); - assert_eq!(fill("abcdefgh\nijkl", 5), "abcde\nfgh\nijkl"); - } - - #[test] - fn break_words_empty_lines() { - assert_eq!( - fill("foo\nbar", &Options::new(2).break_words(false)), - "foo\nbar" - ); - } - - #[test] - fn fill_inplace_empty() { - let mut text = String::from(""); - fill_inplace(&mut text, 80); - assert_eq!(text, ""); - } - - #[test] - fn fill_inplace_simple() { - let mut text = String::from("foo bar baz"); - fill_inplace(&mut text, 10); - assert_eq!(text, "foo bar\nbaz"); - } - - #[test] - fn fill_inplace_multiple_lines() { - let mut text = String::from("Some text to wrap over multiple lines"); - fill_inplace(&mut text, 12); - assert_eq!(text, "Some text to\nwrap over\nmultiple\nlines"); - } - - #[test] - fn fill_inplace_long_word() { - let mut text = String::from("Internationalization is hard"); - fill_inplace(&mut text, 10); - assert_eq!(text, "Internationalization\nis hard"); - } - - #[test] - fn fill_inplace_no_hyphen_splitting() { - let mut text = String::from("A well-chosen example"); - fill_inplace(&mut text, 10); - assert_eq!(text, "A\nwell-chosen\nexample"); - } - - #[test] - fn fill_inplace_newlines() { - let mut text = String::from("foo bar\n\nbaz\n\n\n"); - fill_inplace(&mut text, 10); - assert_eq!(text, "foo bar\n\nbaz\n\n\n"); - } - - #[test] - fn fill_inplace_newlines_reset_line_width() { - let mut text = String::from("1 3 5\n1 3 5 7 9\n1 3 5 7 9 1 3"); - fill_inplace(&mut text, 10); - assert_eq!(text, "1 3 5\n1 3 5 7 9\n1 3 5 7 9\n1 3"); - } - - #[test] - fn fill_inplace_leading_whitespace() { - let mut text = String::from(" foo bar baz"); - fill_inplace(&mut text, 10); - assert_eq!(text, " foo bar\nbaz"); - } - - #[test] - fn fill_inplace_trailing_whitespace() { - let mut text = String::from("foo bar baz "); - fill_inplace(&mut text, 10); - assert_eq!(text, "foo bar\nbaz "); - } - - #[test] - fn fill_inplace_interior_whitespace() { - // To avoid an unwanted indentation of "baz", it is important - // to replace the final ' ' with '\n'. - let mut text = String::from("foo bar baz"); - fill_inplace(&mut text, 10); - assert_eq!(text, "foo bar \nbaz"); - } -} diff --git a/third_party/rust/textwrap/src/fuzzing.rs b/third_party/rust/textwrap/src/fuzzing.rs deleted file mode 100644 index b7ad4812a2f8..000000000000 --- a/third_party/rust/textwrap/src/fuzzing.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Fuzzing helpers. - -use super::Options; -use std::borrow::Cow; - -/// Exposed for fuzzing so we can check the slow path is correct. -pub fn fill_slow_path<'a>(text: &str, options: Options<'_>) -> String { - crate::fill::fill_slow_path(text, options) -} - -/// Exposed for fuzzing so we can check the slow path is correct. -pub fn wrap_single_line<'a>(line: &'a str, options: &Options<'_>, lines: &mut Vec>) { - crate::wrap::wrap_single_line(line, options, lines); -} - -/// Exposed for fuzzing so we can check the slow path is correct. -pub fn wrap_single_line_slow_path<'a>( - line: &'a str, - options: &Options<'_>, - lines: &mut Vec>, -) { - crate::wrap::wrap_single_line_slow_path(line, options, lines) -} diff --git a/third_party/rust/textwrap/src/indentation.rs b/third_party/rust/textwrap/src/indentation.rs deleted file mode 100644 index 2f3a853b3cfd..000000000000 --- a/third_party/rust/textwrap/src/indentation.rs +++ /dev/null @@ -1,347 +0,0 @@ -//! Functions related to adding and removing indentation from lines of -//! text. -//! -//! The functions here can be used to uniformly indent or dedent -//! (unindent) word wrapped lines of text. - -/// Indent each line by the given prefix. -/// -/// # Examples -/// -/// ``` -/// use textwrap::indent; -/// -/// assert_eq!(indent("First line.\nSecond line.\n", " "), -/// " First line.\n Second line.\n"); -/// ``` -/// -/// When indenting, trailing whitespace is stripped from the prefix. -/// This means that empty lines remain empty afterwards: -/// -/// ``` -/// use textwrap::indent; -/// -/// assert_eq!(indent("First line.\n\n\nSecond line.\n", " "), -/// " First line.\n\n\n Second line.\n"); -/// ``` -/// -/// Notice how `"\n\n\n"` remained as `"\n\n\n"`. -/// -/// This feature is useful when you want to indent text and have a -/// space between your prefix and the text. In this case, you _don't_ -/// want a trailing space on empty lines: -/// -/// ``` -/// use textwrap::indent; -/// -/// assert_eq!(indent("foo = 123\n\nprint(foo)\n", "# "), -/// "# foo = 123\n#\n# print(foo)\n"); -/// ``` -/// -/// Notice how `"\n\n"` became `"\n#\n"` instead of `"\n# \n"` which -/// would have trailing whitespace. -/// -/// Leading and trailing whitespace coming from the text itself is -/// kept unchanged: -/// -/// ``` -/// use textwrap::indent; -/// -/// assert_eq!(indent(" \t Foo ", "->"), "-> \t Foo "); -/// ``` -pub fn indent(s: &str, prefix: &str) -> String { - // We know we'll need more than s.len() bytes for the output, but - // without counting '\n' characters (which is somewhat slow), we - // don't know exactly how much. However, we can preemptively do - // the first doubling of the output size. - let mut result = String::with_capacity(2 * s.len()); - let trimmed_prefix = prefix.trim_end(); - for (idx, line) in s.split_terminator('\n').enumerate() { - if idx > 0 { - result.push('\n'); - } - if line.trim().is_empty() { - result.push_str(trimmed_prefix); - } else { - result.push_str(prefix); - } - result.push_str(line); - } - if s.ends_with('\n') { - // split_terminator will have eaten the final '\n'. - result.push('\n'); - } - result -} - -/// Removes common leading whitespace from each line. -/// -/// This function will look at each non-empty line and determine the -/// maximum amount of whitespace that can be removed from all lines: -/// -/// ``` -/// use textwrap::dedent; -/// -/// assert_eq!(dedent(" -/// 1st line -/// 2nd line -/// 3rd line -/// "), " -/// 1st line -/// 2nd line -/// 3rd line -/// "); -/// ``` -pub fn dedent(s: &str) -> String { - let mut prefix = ""; - let mut lines = s.lines(); - - // We first search for a non-empty line to find a prefix. - for line in &mut lines { - let mut whitespace_idx = line.len(); - for (idx, ch) in line.char_indices() { - if !ch.is_whitespace() { - whitespace_idx = idx; - break; - } - } - - // Check if the line had anything but whitespace - if whitespace_idx < line.len() { - prefix = &line[..whitespace_idx]; - break; - } - } - - // We then continue looking through the remaining lines to - // possibly shorten the prefix. - for line in &mut lines { - let mut whitespace_idx = line.len(); - for ((idx, a), b) in line.char_indices().zip(prefix.chars()) { - if a != b { - whitespace_idx = idx; - break; - } - } - - // Check if the line had anything but whitespace and if we - // have found a shorter prefix - if whitespace_idx < line.len() && whitespace_idx < prefix.len() { - prefix = &line[..whitespace_idx]; - } - } - - // We now go over the lines a second time to build the result. - let mut result = String::new(); - for line in s.lines() { - if line.starts_with(prefix) && line.chars().any(|c| !c.is_whitespace()) { - let (_, tail) = line.split_at(prefix.len()); - result.push_str(tail); - } - result.push('\n'); - } - - if result.ends_with('\n') && !s.ends_with('\n') { - let new_len = result.len() - 1; - result.truncate(new_len); - } - - result -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn indent_empty() { - assert_eq!(indent("\n", " "), "\n"); - } - - #[test] - #[rustfmt::skip] - fn indent_nonempty() { - let text = [ - " foo\n", - "bar\n", - " baz\n", - ].join(""); - let expected = [ - "// foo\n", - "// bar\n", - "// baz\n", - ].join(""); - assert_eq!(indent(&text, "// "), expected); - } - - #[test] - #[rustfmt::skip] - fn indent_empty_line() { - let text = [ - " foo", - "bar", - "", - " baz", - ].join("\n"); - let expected = [ - "// foo", - "// bar", - "//", - "// baz", - ].join("\n"); - assert_eq!(indent(&text, "// "), expected); - } - - #[test] - fn dedent_empty() { - assert_eq!(dedent(""), ""); - } - - #[test] - #[rustfmt::skip] - fn dedent_multi_line() { - let x = [ - " foo", - " bar", - " baz", - ].join("\n"); - let y = [ - " foo", - "bar", - " baz" - ].join("\n"); - assert_eq!(dedent(&x), y); - } - - #[test] - #[rustfmt::skip] - fn dedent_empty_line() { - let x = [ - " foo", - " bar", - " ", - " baz" - ].join("\n"); - let y = [ - " foo", - "bar", - "", - " baz" - ].join("\n"); - assert_eq!(dedent(&x), y); - } - - #[test] - #[rustfmt::skip] - fn dedent_blank_line() { - let x = [ - " foo", - "", - " bar", - " foo", - " bar", - " baz", - ].join("\n"); - let y = [ - "foo", - "", - " bar", - " foo", - " bar", - " baz", - ].join("\n"); - assert_eq!(dedent(&x), y); - } - - #[test] - #[rustfmt::skip] - fn dedent_whitespace_line() { - let x = [ - " foo", - " ", - " bar", - " foo", - " bar", - " baz", - ].join("\n"); - let y = [ - "foo", - "", - " bar", - " foo", - " bar", - " baz", - ].join("\n"); - assert_eq!(dedent(&x), y); - } - - #[test] - #[rustfmt::skip] - fn dedent_mixed_whitespace() { - let x = [ - "\tfoo", - " bar", - ].join("\n"); - let y = [ - "\tfoo", - " bar", - ].join("\n"); - assert_eq!(dedent(&x), y); - } - - #[test] - #[rustfmt::skip] - fn dedent_tabbed_whitespace() { - let x = [ - "\t\tfoo", - "\t\t\tbar", - ].join("\n"); - let y = [ - "foo", - "\tbar", - ].join("\n"); - assert_eq!(dedent(&x), y); - } - - #[test] - #[rustfmt::skip] - fn dedent_mixed_tabbed_whitespace() { - let x = [ - "\t \tfoo", - "\t \t\tbar", - ].join("\n"); - let y = [ - "foo", - "\tbar", - ].join("\n"); - assert_eq!(dedent(&x), y); - } - - #[test] - #[rustfmt::skip] - fn dedent_mixed_tabbed_whitespace2() { - let x = [ - "\t \tfoo", - "\t \tbar", - ].join("\n"); - let y = [ - "\tfoo", - " \tbar", - ].join("\n"); - assert_eq!(dedent(&x), y); - } - - #[test] - #[rustfmt::skip] - fn dedent_preserve_no_terminating_newline() { - let x = [ - " foo", - " bar", - ].join("\n"); - let y = [ - "foo", - " bar", - ].join("\n"); - assert_eq!(dedent(&x), y); - } -} diff --git a/third_party/rust/textwrap/src/lib.rs b/third_party/rust/textwrap/src/lib.rs deleted file mode 100644 index 32611c0938c4..000000000000 --- a/third_party/rust/textwrap/src/lib.rs +++ /dev/null @@ -1,235 +0,0 @@ -//! The textwrap library provides functions for word wrapping and -//! indenting text. -//! -//! # Wrapping Text -//! -//! Wrapping text can be very useful in command-line programs where -//! you want to format dynamic output nicely so it looks good in a -//! terminal. A quick example: -//! -//! ``` -//! # #[cfg(feature = "smawk")] { -//! let text = "textwrap: a small library for wrapping text."; -//! assert_eq!(textwrap::wrap(text, 18), -//! vec!["textwrap: a", -//! "small library for", -//! "wrapping text."]); -//! # } -//! ``` -//! -//! The [`wrap()`] function returns the individual lines, use -//! [`fill()`] is you want the lines joined with `'\n'` to form a -//! `String`. -//! -//! If you enable the `hyphenation` Cargo feature, you can get -//! automatic hyphenation for a number of languages: -//! -//! ``` -//! #[cfg(feature = "hyphenation")] { -//! use hyphenation::{Language, Load, Standard}; -//! use textwrap::{wrap, Options, WordSplitter}; -//! -//! let text = "textwrap: a small library for wrapping text."; -//! let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); -//! let options = Options::new(18).word_splitter(WordSplitter::Hyphenation(dictionary)); -//! assert_eq!(wrap(text, &options), -//! vec!["textwrap: a small", -//! "library for wrap-", -//! "ping text."]); -//! } -//! ``` -//! -//! See also the [`unfill()`] and [`refill()`] functions which allow -//! you to manipulate already wrapped text. -//! -//! ## Wrapping Strings at Compile Time -//! -//! If your strings are known at compile time, please take a look at -//! the procedural macros from the [textwrap-macros] crate. -//! -//! ## Displayed Width vs Byte Size -//! -//! To word wrap text, one must know the width of each word so one can -//! know when to break lines. This library will by default measure the -//! width of text using the _displayed width_, not the size in bytes. -//! The `unicode-width` Cargo feature controls this. -//! -//! This is important for non-ASCII text. ASCII characters such as `a` -//! and `!` are simple and take up one column each. This means that -//! the displayed width is equal to the string length in bytes. -//! However, non-ASCII characters and symbols take up more than one -//! byte when UTF-8 encoded: `é` is `0xc3 0xa9` (two bytes) and `⚙` is -//! `0xe2 0x9a 0x99` (three bytes) in UTF-8, respectively. -//! -//! This is why we take care to use the displayed width instead of the -//! byte count when computing line lengths. All functions in this -//! library handle Unicode characters like this when the -//! `unicode-width` Cargo feature is enabled (it is enabled by -//! default). -//! -//! # Indentation and Dedentation -//! -//! The textwrap library also offers functions for adding a prefix to -//! every line of a string and to remove leading whitespace. As an -//! example, [`indent()`] allows you to turn lines of text into a -//! bullet list: -//! -//! ``` -//! let before = "\ -//! foo -//! bar -//! baz -//! "; -//! let after = "\ -//! * foo -//! * bar -//! * baz -//! "; -//! assert_eq!(textwrap::indent(before, "* "), after); -//! ``` -//! -//! Removing leading whitespace is done with [`dedent()`]: -//! -//! ``` -//! let before = " -//! Some -//! indented -//! text -//! "; -//! let after = " -//! Some -//! indented -//! text -//! "; -//! assert_eq!(textwrap::dedent(before), after); -//! ``` -//! -//! # Cargo Features -//! -//! The textwrap library can be slimmed down as needed via a number of -//! Cargo features. This means you only pay for the features you -//! actually use. -//! -//! The full dependency graph, where dashed lines indicate optional -//! dependencies, is shown below: -//! -//! -//! -//! ## Default Features -//! -//! These features are enabled by default: -//! -//! * `unicode-linebreak`: enables finding words using the -//! [unicode-linebreak] crate, which implements the line breaking -//! algorithm described in [Unicode Standard Annex -//! #14](https://www.unicode.org/reports/tr14/). -//! -//! This feature can be disabled if you are happy to find words -//! separated by ASCII space characters only. People wrapping text -//! with emojis or East-Asian characters will want most likely want -//! to enable this feature. See [`WordSeparator`] for details. -//! -//! * `unicode-width`: enables correct width computation of non-ASCII -//! characters via the [unicode-width] crate. Without this feature, -//! every [`char`] is 1 column wide, except for emojis which are 2 -//! columns wide. See [`core::display_width()`] for details. -//! -//! This feature can be disabled if you only need to wrap ASCII -//! text, or if the functions in [`core`] are used directly with -//! [`core::Fragment`]s for which the widths have been computed in -//! other ways. -//! -//! * `smawk`: enables linear-time wrapping of the whole paragraph via -//! the [smawk] crate. See [`wrap_algorithms::wrap_optimal_fit()`] -//! for details on the optimal-fit algorithm. -//! -//! This feature can be disabled if you only ever intend to use -//! [`wrap_algorithms::wrap_first_fit()`]. -//! -//! -//! -//! With Rust 1.64.0, the size impact of the above features on your -//! binary is as follows: -//! -//! | Configuration | Binary Size | Delta | -//! | :--- | ---: | ---: | -//! | quick-and-dirty implementation | 289 KB | — KB | -//! | textwrap without default features | 305 KB | 16 KB | -//! | textwrap with smawk | 317 KB | 28 KB | -//! | textwrap with unicode-width | 309 KB | 20 KB | -//! | textwrap with unicode-linebreak | 342 KB | 53 KB | -//! -//! -//! -//! The above sizes are the stripped sizes and the binary is compiled -//! in release mode with this profile: -//! -//! ```toml -//! [profile.release] -//! lto = true -//! codegen-units = 1 -//! ``` -//! -//! See the [binary-sizes demo] if you want to reproduce these -//! results. -//! -//! ## Optional Features -//! -//! These Cargo features enable new functionality: -//! -//! * `terminal_size`: enables automatic detection of the terminal -//! width via the [terminal_size] crate. See -//! [`Options::with_termwidth()`] for details. -//! -//! * `hyphenation`: enables language-sensitive hyphenation via the -//! [hyphenation] crate. See the [`word_splitters::WordSplitter`] -//! trait for details. -//! -//! [unicode-linebreak]: https://docs.rs/unicode-linebreak/ -//! [unicode-width]: https://docs.rs/unicode-width/ -//! [smawk]: https://docs.rs/smawk/ -//! [binary-sizes demo]: https://github.com/mgeisler/textwrap/tree/master/examples/binary-sizes -//! [textwrap-macros]: https://docs.rs/textwrap-macros/ -//! [terminal_size]: https://docs.rs/terminal_size/ -//! [hyphenation]: https://docs.rs/hyphenation/ - -#![doc(html_root_url = "https://docs.rs/textwrap/0.16.1")] -#![forbid(unsafe_code)] // See https://github.com/mgeisler/textwrap/issues/210 -#![deny(missing_docs)] -#![deny(missing_debug_implementations)] -#![allow(clippy::redundant_field_names)] - -// Make `cargo test` execute the README doctests. -#[cfg(doctest)] -#[doc = include_str!("../README.md")] -mod readme_doctest {} - -pub mod core; -#[cfg(fuzzing)] -pub mod fuzzing; -pub mod word_splitters; -pub mod wrap_algorithms; - -mod columns; -mod fill; -mod indentation; -mod line_ending; -mod options; -mod refill; -#[cfg(feature = "terminal_size")] -mod termwidth; -mod word_separators; -mod wrap; - -pub use columns::wrap_columns; -pub use fill::{fill, fill_inplace}; -pub use indentation::{dedent, indent}; -pub use line_ending::LineEnding; -pub use options::Options; -pub use refill::{refill, unfill}; -#[cfg(feature = "terminal_size")] -pub use termwidth::termwidth; -pub use word_separators::WordSeparator; -pub use word_splitters::WordSplitter; -pub use wrap::wrap; -pub use wrap_algorithms::WrapAlgorithm; diff --git a/third_party/rust/textwrap/src/line_ending.rs b/third_party/rust/textwrap/src/line_ending.rs deleted file mode 100644 index 0514fe5fc0df..000000000000 --- a/third_party/rust/textwrap/src/line_ending.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Line ending detection and conversion. - -use std::fmt::Debug; - -/// Supported line endings. Like in the Rust standard library, two line -/// endings are supported: `\r\n` and `\n` -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum LineEnding { - /// _Carriage return and line feed_ – a line ending sequence - /// historically used in Windows. Corresponds to the sequence - /// of ASCII control characters `0x0D 0x0A` or `\r\n` - CRLF, - /// _Line feed_ – a line ending historically used in Unix. - /// Corresponds to the ASCII control character `0x0A` or `\n` - LF, -} - -impl LineEnding { - /// Turns this [`LineEnding`] value into its ASCII representation. - #[inline] - pub const fn as_str(&self) -> &'static str { - match self { - Self::CRLF => "\r\n", - Self::LF => "\n", - } - } -} - -/// An iterator over the lines of a string, as tuples of string slice -/// and [`LineEnding`] value; it only emits non-empty lines (i.e. having -/// some content before the terminating `\r\n` or `\n`). -/// -/// This struct is used internally by the library. -#[derive(Debug, Clone, Copy)] -pub(crate) struct NonEmptyLines<'a>(pub &'a str); - -impl<'a> Iterator for NonEmptyLines<'a> { - type Item = (&'a str, Option); - - fn next(&mut self) -> Option { - while let Some(lf) = self.0.find('\n') { - if lf == 0 || (lf == 1 && self.0.as_bytes()[lf - 1] == b'\r') { - self.0 = &self.0[(lf + 1)..]; - continue; - } - let trimmed = match self.0.as_bytes()[lf - 1] { - b'\r' => (&self.0[..(lf - 1)], Some(LineEnding::CRLF)), - _ => (&self.0[..lf], Some(LineEnding::LF)), - }; - self.0 = &self.0[(lf + 1)..]; - return Some(trimmed); - } - if self.0.is_empty() { - None - } else { - let line = std::mem::take(&mut self.0); - Some((line, None)) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn non_empty_lines_full_case() { - assert_eq!( - NonEmptyLines("LF\nCRLF\r\n\r\n\nunterminated") - .collect::)>>(), - vec![ - ("LF", Some(LineEnding::LF)), - ("CRLF", Some(LineEnding::CRLF)), - ("unterminated", None), - ] - ); - } - - #[test] - fn non_empty_lines_new_lines_only() { - assert_eq!(NonEmptyLines("\r\n\n\n\r\n").next(), None); - } - - #[test] - fn non_empty_lines_no_input() { - assert_eq!(NonEmptyLines("").next(), None); - } -} diff --git a/third_party/rust/textwrap/src/options.rs b/third_party/rust/textwrap/src/options.rs deleted file mode 100644 index 80e420d195c1..000000000000 --- a/third_party/rust/textwrap/src/options.rs +++ /dev/null @@ -1,300 +0,0 @@ -//! Options for wrapping text. - -use crate::{LineEnding, WordSeparator, WordSplitter, WrapAlgorithm}; - -/// Holds configuration options for wrapping and filling text. -#[non_exhaustive] -#[derive(Debug, Clone)] -pub struct Options<'a> { - /// The width in columns at which the text will be wrapped. - pub width: usize, - /// Line ending used for breaking lines. - pub line_ending: LineEnding, - /// Indentation used for the first line of output. See the - /// [`Options::initial_indent`] method. - pub initial_indent: &'a str, - /// Indentation used for subsequent lines of output. See the - /// [`Options::subsequent_indent`] method. - pub subsequent_indent: &'a str, - /// Allow long words to be broken if they cannot fit on a line. - /// When set to `false`, some lines may be longer than - /// `self.width`. See the [`Options::break_words`] method. - pub break_words: bool, - /// Wrapping algorithm to use, see the implementations of the - /// [`WrapAlgorithm`] trait for details. - pub wrap_algorithm: WrapAlgorithm, - /// The line breaking algorithm to use, see the [`WordSeparator`] - /// trait for an overview and possible implementations. - pub word_separator: WordSeparator, - /// The method for splitting words. This can be used to prohibit - /// splitting words on hyphens, or it can be used to implement - /// language-aware machine hyphenation. - pub word_splitter: WordSplitter, -} - -impl<'a> From<&'a Options<'a>> for Options<'a> { - fn from(options: &'a Options<'a>) -> Self { - Self { - width: options.width, - line_ending: options.line_ending, - initial_indent: options.initial_indent, - subsequent_indent: options.subsequent_indent, - break_words: options.break_words, - word_separator: options.word_separator, - wrap_algorithm: options.wrap_algorithm, - word_splitter: options.word_splitter.clone(), - } - } -} - -impl<'a> From for Options<'a> { - fn from(width: usize) -> Self { - Options::new(width) - } -} - -impl<'a> Options<'a> { - /// Creates a new [`Options`] with the specified width. - /// - /// The other fields are given default values as follows: - /// - /// ``` - /// # use textwrap::{LineEnding, Options, WordSplitter, WordSeparator, WrapAlgorithm}; - /// # let width = 80; - /// let options = Options::new(width); - /// assert_eq!(options.line_ending, LineEnding::LF); - /// assert_eq!(options.initial_indent, ""); - /// assert_eq!(options.subsequent_indent, ""); - /// assert_eq!(options.break_words, true); - /// - /// #[cfg(feature = "unicode-linebreak")] - /// assert_eq!(options.word_separator, WordSeparator::UnicodeBreakProperties); - /// #[cfg(not(feature = "unicode-linebreak"))] - /// assert_eq!(options.word_separator, WordSeparator::AsciiSpace); - /// - /// #[cfg(feature = "smawk")] - /// assert_eq!(options.wrap_algorithm, WrapAlgorithm::new_optimal_fit()); - /// #[cfg(not(feature = "smawk"))] - /// assert_eq!(options.wrap_algorithm, WrapAlgorithm::FirstFit); - /// - /// assert_eq!(options.word_splitter, WordSplitter::HyphenSplitter); - /// ``` - /// - /// Note that the default word separator and wrap algorithms - /// changes based on the available Cargo features. The best - /// available algorithms are used by default. - pub const fn new(width: usize) -> Self { - Options { - width, - line_ending: LineEnding::LF, - initial_indent: "", - subsequent_indent: "", - break_words: true, - word_separator: WordSeparator::new(), - wrap_algorithm: WrapAlgorithm::new(), - word_splitter: WordSplitter::HyphenSplitter, - } - } - - /// Change [`self.line_ending`]. This specifies which of the - /// supported line endings should be used to break the lines of the - /// input text. - /// - /// # Examples - /// - /// ``` - /// use textwrap::{refill, LineEnding, Options}; - /// - /// let options = Options::new(15).line_ending(LineEnding::CRLF); - /// assert_eq!(refill("This is a little example.", options), - /// "This is a\r\nlittle example."); - /// ``` - /// - /// [`self.line_ending`]: #structfield.line_ending - pub fn line_ending(self, line_ending: LineEnding) -> Self { - Options { - line_ending, - ..self - } - } - - /// Set [`self.width`] to the given value. - /// - /// [`self.width`]: #structfield.width - pub fn width(self, width: usize) -> Self { - Options { width, ..self } - } - - /// Change [`self.initial_indent`]. The initial indentation is - /// used on the very first line of output. - /// - /// # Examples - /// - /// Classic paragraph indentation can be achieved by specifying an - /// initial indentation and wrapping each paragraph by itself: - /// - /// ``` - /// use textwrap::{wrap, Options}; - /// - /// let options = Options::new(16).initial_indent(" "); - /// assert_eq!(wrap("This is a little example.", options), - /// vec![" This is a", - /// "little example."]); - /// ``` - /// - /// [`self.initial_indent`]: #structfield.initial_indent - pub fn initial_indent(self, initial_indent: &'a str) -> Self { - Options { - initial_indent, - ..self - } - } - - /// Change [`self.subsequent_indent`]. The subsequent indentation - /// is used on lines following the first line of output. - /// - /// # Examples - /// - /// Combining initial and subsequent indentation lets you format a - /// single paragraph as a bullet list: - /// - /// ``` - /// use textwrap::{wrap, Options}; - /// - /// let options = Options::new(12) - /// .initial_indent("* ") - /// .subsequent_indent(" "); - /// #[cfg(feature = "smawk")] - /// assert_eq!(wrap("This is a little example.", options), - /// vec!["* This is", - /// " a little", - /// " example."]); - /// - /// // Without the `smawk` feature, the wrapping is a little different: - /// #[cfg(not(feature = "smawk"))] - /// assert_eq!(wrap("This is a little example.", options), - /// vec!["* This is a", - /// " little", - /// " example."]); - /// ``` - /// - /// [`self.subsequent_indent`]: #structfield.subsequent_indent - pub fn subsequent_indent(self, subsequent_indent: &'a str) -> Self { - Options { - subsequent_indent, - ..self - } - } - - /// Change [`self.break_words`]. This controls if words longer - /// than `self.width` can be broken, or if they will be left - /// sticking out into the right margin. - /// - /// See [`Options::word_splitter`] instead if you want to control - /// hyphenation. - /// - /// # Examples - /// - /// ``` - /// use textwrap::{wrap, Options}; - /// - /// let options = Options::new(4).break_words(true); - /// assert_eq!(wrap("This is a little example.", options), - /// vec!["This", - /// "is a", - /// "litt", - /// "le", - /// "exam", - /// "ple."]); - /// ``` - /// - /// [`self.break_words`]: #structfield.break_words - pub fn break_words(self, break_words: bool) -> Self { - Options { - break_words, - ..self - } - } - - /// Change [`self.word_separator`]. - /// - /// See the [`WordSeparator`] trait for details on the choices. - /// - /// [`self.word_separator`]: #structfield.word_separator - pub fn word_separator(self, word_separator: WordSeparator) -> Options<'a> { - Options { - word_separator, - ..self - } - } - - /// Change [`self.wrap_algorithm`]. - /// - /// See the [`WrapAlgorithm`] trait for details on the choices. - /// - /// [`self.wrap_algorithm`]: #structfield.wrap_algorithm - pub fn wrap_algorithm(self, wrap_algorithm: WrapAlgorithm) -> Options<'a> { - Options { - wrap_algorithm, - ..self - } - } - - /// Change [`self.word_splitter`]. The [`WordSplitter`] is used to - /// fit part of a word into the current line when wrapping text. - /// - /// See [`Options::break_words`] instead if you want to control the - /// handling of words longer than the line width. - /// - /// # Examples - /// - /// ``` - /// use textwrap::{wrap, Options, WordSplitter}; - /// - /// // The default is WordSplitter::HyphenSplitter. - /// let options = Options::new(5); - /// assert_eq!(wrap("foo-bar-baz", &options), - /// vec!["foo-", "bar-", "baz"]); - /// - /// // The word is now so long that break_words kick in: - /// let options = Options::new(5) - /// .word_splitter(WordSplitter::NoHyphenation); - /// assert_eq!(wrap("foo-bar-baz", &options), - /// vec!["foo-b", "ar-ba", "z"]); - /// - /// // If you want to breaks at all, disable both: - /// let options = Options::new(5) - /// .break_words(false) - /// .word_splitter(WordSplitter::NoHyphenation); - /// assert_eq!(wrap("foo-bar-baz", &options), - /// vec!["foo-bar-baz"]); - /// ``` - /// - /// [`self.word_splitter`]: #structfield.word_splitter - pub fn word_splitter(self, word_splitter: WordSplitter) -> Options<'a> { - Options { - word_splitter, - ..self - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn options_agree_with_usize() { - let opt_usize = Options::from(42_usize); - let opt_options = Options::new(42); - - assert_eq!(opt_usize.width, opt_options.width); - assert_eq!(opt_usize.initial_indent, opt_options.initial_indent); - assert_eq!(opt_usize.subsequent_indent, opt_options.subsequent_indent); - assert_eq!(opt_usize.break_words, opt_options.break_words); - assert_eq!( - opt_usize.word_splitter.split_points("hello-world"), - opt_options.word_splitter.split_points("hello-world") - ); - } -} diff --git a/third_party/rust/textwrap/src/refill.rs b/third_party/rust/textwrap/src/refill.rs deleted file mode 100644 index 1be85f04eb39..000000000000 --- a/third_party/rust/textwrap/src/refill.rs +++ /dev/null @@ -1,352 +0,0 @@ -//! Functionality for unfilling and refilling text. - -use crate::core::display_width; -use crate::line_ending::NonEmptyLines; -use crate::{fill, LineEnding, Options}; - -/// Unpack a paragraph of already-wrapped text. -/// -/// This function attempts to recover the original text from a single -/// paragraph of wrapped text, such as what [`fill()`] would produce. -/// This means that it turns -/// -/// ```text -/// textwrap: a small -/// library for -/// wrapping text. -/// ``` -/// -/// back into -/// -/// ```text -/// textwrap: a small library for wrapping text. -/// ``` -/// -/// In addition, it will recognize a common prefix and a common line -/// ending among the lines. -/// -/// The prefix of the first line is returned in -/// [`Options::initial_indent`] and the prefix (if any) of the the -/// other lines is returned in [`Options::subsequent_indent`]. -/// -/// Line ending is returned in [`Options::line_ending`]. If line ending -/// can not be confidently detected (mixed or no line endings in the -/// input), [`LineEnding::LF`] will be returned. -/// -/// In addition to `' '`, the prefixes can consist of characters used -/// for unordered lists (`'-'`, `'+'`, and `'*'`) and block quotes -/// (`'>'`) in Markdown as well as characters often used for inline -/// comments (`'#'` and `'/'`). -/// -/// The text must come from a single wrapped paragraph. This means -/// that there can be no empty lines (`"\n\n"` or `"\r\n\r\n"`) within -/// the text. It is unspecified what happens if `unfill` is called on -/// more than one paragraph of text. -/// -/// # Examples -/// -/// ``` -/// use textwrap::{LineEnding, unfill}; -/// -/// let (text, options) = unfill("\ -/// * This is an -/// example of -/// a list item. -/// "); -/// -/// assert_eq!(text, "This is an example of a list item.\n"); -/// assert_eq!(options.initial_indent, "* "); -/// assert_eq!(options.subsequent_indent, " "); -/// assert_eq!(options.line_ending, LineEnding::LF); -/// ``` -pub fn unfill(text: &str) -> (String, Options<'_>) { - let prefix_chars: &[_] = &[' ', '-', '+', '*', '>', '#', '/']; - - let mut options = Options::new(0); - for (idx, line) in text.lines().enumerate() { - options.width = std::cmp::max(options.width, display_width(line)); - let without_prefix = line.trim_start_matches(prefix_chars); - let prefix = &line[..line.len() - without_prefix.len()]; - - if idx == 0 { - options.initial_indent = prefix; - } else if idx == 1 { - options.subsequent_indent = prefix; - } else if idx > 1 { - for ((idx, x), y) in prefix.char_indices().zip(options.subsequent_indent.chars()) { - if x != y { - options.subsequent_indent = &prefix[..idx]; - break; - } - } - if prefix.len() < options.subsequent_indent.len() { - options.subsequent_indent = prefix; - } - } - } - - let mut unfilled = String::with_capacity(text.len()); - let mut detected_line_ending = None; - - for (idx, (line, ending)) in NonEmptyLines(text).enumerate() { - if idx == 0 { - unfilled.push_str(&line[options.initial_indent.len()..]); - } else { - unfilled.push(' '); - unfilled.push_str(&line[options.subsequent_indent.len()..]); - } - match (detected_line_ending, ending) { - (None, Some(_)) => detected_line_ending = ending, - (Some(LineEnding::CRLF), Some(LineEnding::LF)) => detected_line_ending = ending, - _ => (), - } - } - - // Add back a line ending if `text` ends with the one we detect. - if let Some(line_ending) = detected_line_ending { - if text.ends_with(line_ending.as_str()) { - unfilled.push_str(line_ending.as_str()); - } - } - - options.line_ending = detected_line_ending.unwrap_or(LineEnding::LF); - (unfilled, options) -} - -/// Refill a paragraph of wrapped text with a new width. -/// -/// This function will first use [`unfill()`] to remove newlines from -/// the text. Afterwards the text is filled again using [`fill()`]. -/// -/// The `new_width_or_options` argument specify the new width and can -/// specify other options as well — except for -/// [`Options::initial_indent`] and [`Options::subsequent_indent`], -/// which are deduced from `filled_text`. -/// -/// # Examples -/// -/// ``` -/// use textwrap::refill; -/// -/// // Some loosely wrapped text. The "> " prefix is recognized automatically. -/// let text = "\ -/// > Memory -/// > safety without garbage -/// > collection. -/// "; -/// -/// assert_eq!(refill(text, 20), "\ -/// > Memory safety -/// > without garbage -/// > collection. -/// "); -/// -/// assert_eq!(refill(text, 40), "\ -/// > Memory safety without garbage -/// > collection. -/// "); -/// -/// assert_eq!(refill(text, 60), "\ -/// > Memory safety without garbage collection. -/// "); -/// ``` -/// -/// You can also reshape bullet points: -/// -/// ``` -/// use textwrap::refill; -/// -/// let text = "\ -/// - This is my -/// list item. -/// "; -/// -/// assert_eq!(refill(text, 20), "\ -/// - This is my list -/// item. -/// "); -/// ``` -pub fn refill<'a, Opt>(filled_text: &str, new_width_or_options: Opt) -> String -where - Opt: Into>, -{ - let mut new_options = new_width_or_options.into(); - let (text, options) = unfill(filled_text); - // The original line ending is kept by `unfill`. - let stripped = text.strip_suffix(options.line_ending.as_str()); - let new_line_ending = new_options.line_ending.as_str(); - - new_options.initial_indent = options.initial_indent; - new_options.subsequent_indent = options.subsequent_indent; - let mut refilled = fill(stripped.unwrap_or(&text), new_options); - - // Add back right line ending if we stripped one off above. - if stripped.is_some() { - refilled.push_str(new_line_ending); - } - refilled -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn unfill_simple() { - let (text, options) = unfill("foo\nbar"); - assert_eq!(text, "foo bar"); - assert_eq!(options.width, 3); - assert_eq!(options.line_ending, LineEnding::LF); - } - - #[test] - fn unfill_no_new_line() { - let (text, options) = unfill("foo bar"); - assert_eq!(text, "foo bar"); - assert_eq!(options.width, 7); - assert_eq!(options.line_ending, LineEnding::LF); - } - - #[test] - fn unfill_simple_crlf() { - let (text, options) = unfill("foo\r\nbar"); - assert_eq!(text, "foo bar"); - assert_eq!(options.width, 3); - assert_eq!(options.line_ending, LineEnding::CRLF); - } - - #[test] - fn unfill_mixed_new_lines() { - let (text, options) = unfill("foo\r\nbar\nbaz"); - assert_eq!(text, "foo bar baz"); - assert_eq!(options.width, 3); - assert_eq!(options.line_ending, LineEnding::LF); - } - - #[test] - fn test_unfill_consecutive_different_prefix() { - let (text, options) = unfill("foo\n*\n/"); - assert_eq!(text, "foo * /"); - assert_eq!(options.width, 3); - assert_eq!(options.line_ending, LineEnding::LF); - } - - #[test] - fn unfill_trailing_newlines() { - let (text, options) = unfill("foo\nbar\n\n\n"); - assert_eq!(text, "foo bar\n"); - assert_eq!(options.width, 3); - } - - #[test] - fn unfill_mixed_trailing_newlines() { - let (text, options) = unfill("foo\r\nbar\n\r\n\n"); - assert_eq!(text, "foo bar\n"); - assert_eq!(options.width, 3); - assert_eq!(options.line_ending, LineEnding::LF); - } - - #[test] - fn unfill_trailing_crlf() { - let (text, options) = unfill("foo bar\r\n"); - assert_eq!(text, "foo bar\r\n"); - assert_eq!(options.width, 7); - assert_eq!(options.line_ending, LineEnding::CRLF); - } - - #[test] - fn unfill_initial_indent() { - let (text, options) = unfill(" foo\nbar\nbaz"); - assert_eq!(text, "foo bar baz"); - assert_eq!(options.width, 5); - assert_eq!(options.initial_indent, " "); - } - - #[test] - fn unfill_differing_indents() { - let (text, options) = unfill(" foo\n bar\n baz"); - assert_eq!(text, "foo bar baz"); - assert_eq!(options.width, 7); - assert_eq!(options.initial_indent, " "); - assert_eq!(options.subsequent_indent, " "); - } - - #[test] - fn unfill_list_item() { - let (text, options) = unfill("* foo\n bar\n baz"); - assert_eq!(text, "foo bar baz"); - assert_eq!(options.width, 5); - assert_eq!(options.initial_indent, "* "); - assert_eq!(options.subsequent_indent, " "); - } - - #[test] - fn unfill_multiple_char_prefix() { - let (text, options) = unfill(" // foo bar\n // baz\n // quux"); - assert_eq!(text, "foo bar baz quux"); - assert_eq!(options.width, 14); - assert_eq!(options.initial_indent, " // "); - assert_eq!(options.subsequent_indent, " // "); - } - - #[test] - fn unfill_block_quote() { - let (text, options) = unfill("> foo\n> bar\n> baz"); - assert_eq!(text, "foo bar baz"); - assert_eq!(options.width, 5); - assert_eq!(options.initial_indent, "> "); - assert_eq!(options.subsequent_indent, "> "); - } - - #[test] - fn unfill_only_prefixes_issue_466() { - // Test that we don't crash if the first line has only prefix - // chars *and* the second line is shorter than the first line. - let (text, options) = unfill("######\nfoo"); - assert_eq!(text, " foo"); - assert_eq!(options.width, 6); - assert_eq!(options.initial_indent, "######"); - assert_eq!(options.subsequent_indent, ""); - } - - #[test] - fn unfill_trailing_newlines_issue_466() { - // Test that we don't crash on a '\r' following a string of - // '\n'. The problem was that we removed both kinds of - // characters in one code path, but not in the other. - let (text, options) = unfill("foo\n##\n\n\r"); - // The \n\n changes subsequent_indent to "". - assert_eq!(text, "foo ## \r"); - assert_eq!(options.width, 3); - assert_eq!(options.initial_indent, ""); - assert_eq!(options.subsequent_indent, ""); - } - - #[test] - fn unfill_whitespace() { - assert_eq!(unfill("foo bar").0, "foo bar"); - } - - #[test] - fn refill_convert_lf_to_crlf() { - let options = Options::new(5).line_ending(LineEnding::CRLF); - assert_eq!(refill("foo\nbar\n", options), "foo\r\nbar\r\n",); - } - - #[test] - fn refill_convert_crlf_to_lf() { - let options = Options::new(5).line_ending(LineEnding::LF); - assert_eq!(refill("foo\r\nbar\r\n", options), "foo\nbar\n",); - } - - #[test] - fn refill_convert_mixed_newlines() { - let options = Options::new(5).line_ending(LineEnding::CRLF); - assert_eq!(refill("foo\r\nbar\n", options), "foo\r\nbar\r\n",); - } - - #[test] - fn refill_defaults_to_lf() { - assert_eq!(refill("foo bar baz", 5), "foo\nbar\nbaz"); - } -} diff --git a/third_party/rust/textwrap/src/termwidth.rs b/third_party/rust/textwrap/src/termwidth.rs deleted file mode 100644 index 5c66191b771e..000000000000 --- a/third_party/rust/textwrap/src/termwidth.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Functions related to the terminal size. - -use crate::Options; - -/// Return the current terminal width. -/// -/// If the terminal width cannot be determined (typically because the -/// standard output is not connected to a terminal), a default width -/// of 80 characters will be used. -/// -/// # Examples -/// -/// Create an [`Options`] for wrapping at the current terminal width -/// with a two column margin to the left and the right: -/// -/// ```no_run -/// use textwrap::{termwidth, Options}; -/// -/// let width = termwidth() - 4; // Two columns on each side. -/// let options = Options::new(width) -/// .initial_indent(" ") -/// .subsequent_indent(" "); -/// ``` -/// -/// **Note:** Only available when the `terminal_size` Cargo feature is -/// enabled. -pub fn termwidth() -> usize { - terminal_size::terminal_size().map_or(80, |(terminal_size::Width(w), _)| w.into()) -} - -impl<'a> Options<'a> { - /// Creates a new [`Options`] with `width` set to the current - /// terminal width. If the terminal width cannot be determined - /// (typically because the standard input and output is not - /// connected to a terminal), a width of 80 characters will be - /// used. Other settings use the same defaults as - /// [`Options::new`]. - /// - /// Equivalent to: - /// - /// ```no_run - /// use textwrap::{termwidth, Options}; - /// - /// let options = Options::new(termwidth()); - /// ``` - /// - /// **Note:** Only available when the `terminal_size` feature is - /// enabled. - pub fn with_termwidth() -> Self { - Self::new(termwidth()) - } -} diff --git a/third_party/rust/textwrap/src/word_separators.rs b/third_party/rust/textwrap/src/word_separators.rs deleted file mode 100644 index e06e9b88aa3d..000000000000 --- a/third_party/rust/textwrap/src/word_separators.rs +++ /dev/null @@ -1,481 +0,0 @@ -//! Functionality for finding words. -//! -//! In order to wrap text, we need to know where the legal break -//! points are, i.e., where the words of the text are. This means that -//! we need to define what a "word" is. -//! -//! A simple approach is to simply split the text on whitespace, but -//! this does not work for East-Asian languages such as Chinese or -//! Japanese where there are no spaces between words. Breaking a long -//! sequence of emojis is another example where line breaks might be -//! wanted even if there are no whitespace to be found. -//! -//! The [`WordSeparator`] enum is responsible for determining where -//! there words are in a line of text. Please refer to the enum and -//! its variants for more information. - -#[cfg(feature = "unicode-linebreak")] -use crate::core::skip_ansi_escape_sequence; -use crate::core::Word; - -/// Describes where words occur in a line of text. -/// -/// The simplest approach is say that words are separated by one or -/// more ASCII spaces (`' '`). This works for Western languages -/// without emojis. A more complex approach is to use the Unicode line -/// breaking algorithm, which finds break points in non-ASCII text. -/// -/// The line breaks occur between words, please see -/// [`WordSplitter`](crate::WordSplitter) for options of how to handle -/// hyphenation of individual words. -/// -/// # Examples -/// -/// ``` -/// use textwrap::core::Word; -/// use textwrap::WordSeparator::AsciiSpace; -/// -/// let words = AsciiSpace.find_words("Hello World!").collect::>(); -/// assert_eq!(words, vec![Word::from("Hello "), Word::from("World!")]); -/// ``` -#[derive(Clone, Copy)] -pub enum WordSeparator { - /// Find words by splitting on runs of `' '` characters. - /// - /// # Examples - /// - /// ``` - /// use textwrap::core::Word; - /// use textwrap::WordSeparator::AsciiSpace; - /// - /// let words = AsciiSpace.find_words("Hello World!").collect::>(); - /// assert_eq!(words, vec![Word::from("Hello "), - /// Word::from("World!")]); - /// ``` - AsciiSpace, - - /// Split `line` into words using Unicode break properties. - /// - /// This word separator uses the Unicode line breaking algorithm - /// described in [Unicode Standard Annex - /// #14](https://www.unicode.org/reports/tr14/) to find legal places - /// to break lines. There is a small difference in that the U+002D - /// (Hyphen-Minus) and U+00AD (Soft Hyphen) don’t create a line break: - /// to allow a line break at a hyphen, use - /// [`WordSplitter::HyphenSplitter`](crate::WordSplitter::HyphenSplitter). - /// Soft hyphens are not currently supported. - /// - /// # Examples - /// - /// Unlike [`WordSeparator::AsciiSpace`], the Unicode line - /// breaking algorithm will find line break opportunities between - /// some characters with no intervening whitespace: - /// - /// ``` - /// #[cfg(feature = "unicode-linebreak")] { - /// use textwrap::core::Word; - /// use textwrap::WordSeparator::UnicodeBreakProperties; - /// - /// assert_eq!(UnicodeBreakProperties.find_words("Emojis: 😂😍").collect::>(), - /// vec![Word::from("Emojis: "), - /// Word::from("😂"), - /// Word::from("😍")]); - /// - /// assert_eq!(UnicodeBreakProperties.find_words("CJK: 你好").collect::>(), - /// vec![Word::from("CJK: "), - /// Word::from("你"), - /// Word::from("好")]); - /// } - /// ``` - /// - /// A U+2060 (Word Joiner) character can be inserted if you want to - /// manually override the defaults and keep the characters together: - /// - /// ``` - /// #[cfg(feature = "unicode-linebreak")] { - /// use textwrap::core::Word; - /// use textwrap::WordSeparator::UnicodeBreakProperties; - /// - /// assert_eq!(UnicodeBreakProperties.find_words("Emojis: 😂\u{2060}😍").collect::>(), - /// vec![Word::from("Emojis: "), - /// Word::from("😂\u{2060}😍")]); - /// } - /// ``` - /// - /// The Unicode line breaking algorithm will also automatically - /// suppress break breaks around certain punctuation characters:: - /// - /// ``` - /// #[cfg(feature = "unicode-linebreak")] { - /// use textwrap::core::Word; - /// use textwrap::WordSeparator::UnicodeBreakProperties; - /// - /// assert_eq!(UnicodeBreakProperties.find_words("[ foo ] bar !").collect::>(), - /// vec![Word::from("[ foo ] "), - /// Word::from("bar !")]); - /// } - /// ``` - #[cfg(feature = "unicode-linebreak")] - UnicodeBreakProperties, - - /// Find words using a custom word separator - Custom(fn(line: &str) -> Box> + '_>), -} - -impl PartialEq for WordSeparator { - /// Compare two word separators. - /// - /// ``` - /// use textwrap::WordSeparator; - /// - /// assert_eq!(WordSeparator::AsciiSpace, WordSeparator::AsciiSpace); - /// #[cfg(feature = "unicode-linebreak")] { - /// assert_eq!(WordSeparator::UnicodeBreakProperties, - /// WordSeparator::UnicodeBreakProperties); - /// } - /// ``` - /// - /// Note that `WordSeparator::Custom` values never compare equal: - /// - /// ``` - /// use textwrap::WordSeparator; - /// use textwrap::core::Word; - /// fn word_separator(line: &str) -> Box> + '_> { - /// Box::new(line.split_inclusive(' ').map(Word::from)) - /// } - /// assert_ne!(WordSeparator::Custom(word_separator), - /// WordSeparator::Custom(word_separator)); - /// ``` - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (WordSeparator::AsciiSpace, WordSeparator::AsciiSpace) => true, - #[cfg(feature = "unicode-linebreak")] - (WordSeparator::UnicodeBreakProperties, WordSeparator::UnicodeBreakProperties) => true, - (_, _) => false, - } - } -} - -impl std::fmt::Debug for WordSeparator { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - WordSeparator::AsciiSpace => f.write_str("AsciiSpace"), - #[cfg(feature = "unicode-linebreak")] - WordSeparator::UnicodeBreakProperties => f.write_str("UnicodeBreakProperties"), - WordSeparator::Custom(_) => f.write_str("Custom(...)"), - } - } -} - -impl WordSeparator { - /// Create a new word separator. - /// - /// The best available algorithm is used by default, i.e., - /// [`WordSeparator::UnicodeBreakProperties`] if available, - /// otherwise [`WordSeparator::AsciiSpace`]. - pub const fn new() -> Self { - #[cfg(feature = "unicode-linebreak")] - { - WordSeparator::UnicodeBreakProperties - } - - #[cfg(not(feature = "unicode-linebreak"))] - { - WordSeparator::AsciiSpace - } - } - - // This function should really return impl Iterator, but - // this isn't possible until Rust supports higher-kinded types: - // https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md - /// Find all words in `line`. - pub fn find_words<'a>(&self, line: &'a str) -> Box> + 'a> { - match self { - WordSeparator::AsciiSpace => find_words_ascii_space(line), - #[cfg(feature = "unicode-linebreak")] - WordSeparator::UnicodeBreakProperties => find_words_unicode_break_properties(line), - WordSeparator::Custom(func) => func(line), - } - } -} - -fn find_words_ascii_space<'a>(line: &'a str) -> Box> + 'a> { - let mut start = 0; - let mut in_whitespace = false; - let mut char_indices = line.char_indices(); - - Box::new(std::iter::from_fn(move || { - for (idx, ch) in char_indices.by_ref() { - if in_whitespace && ch != ' ' { - let word = Word::from(&line[start..idx]); - start = idx; - in_whitespace = ch == ' '; - return Some(word); - } - - in_whitespace = ch == ' '; - } - - if start < line.len() { - let word = Word::from(&line[start..]); - start = line.len(); - return Some(word); - } - - None - })) -} - -// Strip all ANSI escape sequences from `text`. -#[cfg(feature = "unicode-linebreak")] -fn strip_ansi_escape_sequences(text: &str) -> String { - let mut result = String::with_capacity(text.len()); - - let mut chars = text.chars(); - while let Some(ch) = chars.next() { - if skip_ansi_escape_sequence(ch, &mut chars) { - continue; - } - result.push(ch); - } - - result -} - -/// Soft hyphen, also knows as a “shy hyphen”. Should show up as ‘-’ -/// if a line is broken at this point, and otherwise be invisible. -/// Textwrap does not currently support breaking words at soft -/// hyphens. -#[cfg(feature = "unicode-linebreak")] -const SHY: char = '\u{00ad}'; - -/// Find words in line. ANSI escape sequences are ignored in `line`. -#[cfg(feature = "unicode-linebreak")] -fn find_words_unicode_break_properties<'a>( - line: &'a str, -) -> Box> + 'a> { - // Construct an iterator over (original index, stripped index) - // tuples. We find the Unicode linebreaks on a stripped string, - // but we need the original indices so we can form words based on - // the original string. - let mut last_stripped_idx = 0; - let mut char_indices = line.char_indices(); - let mut idx_map = std::iter::from_fn(move || match char_indices.next() { - Some((orig_idx, ch)) => { - let stripped_idx = last_stripped_idx; - if !skip_ansi_escape_sequence(ch, &mut char_indices.by_ref().map(|(_, ch)| ch)) { - last_stripped_idx += ch.len_utf8(); - } - Some((orig_idx, stripped_idx)) - } - None => None, - }); - - let stripped = strip_ansi_escape_sequences(line); - let mut opportunities = unicode_linebreak::linebreaks(&stripped) - .filter(|(idx, _)| { - #[allow(clippy::match_like_matches_macro)] - match &stripped[..*idx].chars().next_back() { - // We suppress breaks at ‘-’ since we want to control - // this via the WordSplitter. - Some('-') => false, - // Soft hyphens are currently not supported since we - // require all `Word` fragments to be continuous in - // the input string. - Some(SHY) => false, - // Other breaks should be fine! - _ => true, - } - }) - .collect::>() - .into_iter(); - - // Remove final break opportunity, we will add it below using - // &line[start..]; This ensures that we correctly include a - // trailing ANSI escape sequence. - opportunities.next_back(); - - let mut start = 0; - Box::new(std::iter::from_fn(move || { - for (idx, _) in opportunities.by_ref() { - if let Some((orig_idx, _)) = idx_map.find(|&(_, stripped_idx)| stripped_idx == idx) { - let word = Word::from(&line[start..orig_idx]); - start = orig_idx; - return Some(word); - } - } - - if start < line.len() { - let word = Word::from(&line[start..]); - start = line.len(); - return Some(word); - } - - None - })) -} - -#[cfg(test)] -mod tests { - use super::WordSeparator::*; - use super::*; - - // Like assert_eq!, but the left expression is an iterator. - macro_rules! assert_iter_eq { - ($left:expr, $right:expr) => { - assert_eq!($left.collect::>(), $right); - }; - } - - fn to_words(words: Vec<&str>) -> Vec> { - words.into_iter().map(Word::from).collect() - } - - macro_rules! test_find_words { - ($ascii_name:ident, - $unicode_name:ident, - $([ $line:expr, $ascii_words:expr, $unicode_words:expr ]),+) => { - #[test] - fn $ascii_name() { - $( - let expected_words = to_words($ascii_words.to_vec()); - let actual_words = WordSeparator::AsciiSpace - .find_words($line) - .collect::>(); - assert_eq!(actual_words, expected_words, "Line: {:?}", $line); - )+ - } - - #[test] - #[cfg(feature = "unicode-linebreak")] - fn $unicode_name() { - $( - let expected_words = to_words($unicode_words.to_vec()); - let actual_words = WordSeparator::UnicodeBreakProperties - .find_words($line) - .collect::>(); - assert_eq!(actual_words, expected_words, "Line: {:?}", $line); - )+ - } - }; - } - - test_find_words!(ascii_space_empty, unicode_empty, ["", [], []]); - - test_find_words!( - ascii_single_word, - unicode_single_word, - ["foo", ["foo"], ["foo"]] - ); - - test_find_words!( - ascii_two_words, - unicode_two_words, - ["foo bar", ["foo ", "bar"], ["foo ", "bar"]] - ); - - test_find_words!( - ascii_multiple_words, - unicode_multiple_words, - ["foo bar", ["foo ", "bar"], ["foo ", "bar"]], - ["x y z", ["x ", "y ", "z"], ["x ", "y ", "z"]] - ); - - test_find_words!( - ascii_only_whitespace, - unicode_only_whitespace, - [" ", [" "], [" "]], - [" ", [" "], [" "]] - ); - - test_find_words!( - ascii_inter_word_whitespace, - unicode_inter_word_whitespace, - ["foo bar", ["foo ", "bar"], ["foo ", "bar"]] - ); - - test_find_words!( - ascii_trailing_whitespace, - unicode_trailing_whitespace, - ["foo ", ["foo "], ["foo "]] - ); - - test_find_words!( - ascii_leading_whitespace, - unicode_leading_whitespace, - [" foo", [" ", "foo"], [" ", "foo"]] - ); - - test_find_words!( - ascii_multi_column_char, - unicode_multi_column_char, - ["\u{1f920}", ["\u{1f920}"], ["\u{1f920}"]] // cowboy emoji 🤠 - ); - - test_find_words!( - ascii_hyphens, - unicode_hyphens, - ["foo-bar", ["foo-bar"], ["foo-bar"]], - ["foo- bar", ["foo- ", "bar"], ["foo- ", "bar"]], - ["foo - bar", ["foo ", "- ", "bar"], ["foo ", "- ", "bar"]], - ["foo -bar", ["foo ", "-bar"], ["foo ", "-bar"]] - ); - - test_find_words!( - ascii_newline, - unicode_newline, - ["foo\nbar", ["foo\nbar"], ["foo\n", "bar"]] - ); - - test_find_words!( - ascii_tab, - unicode_tab, - ["foo\tbar", ["foo\tbar"], ["foo\t", "bar"]] - ); - - test_find_words!( - ascii_non_breaking_space, - unicode_non_breaking_space, - ["foo\u{00A0}bar", ["foo\u{00A0}bar"], ["foo\u{00A0}bar"]] - ); - - #[test] - #[cfg(unix)] - fn find_words_colored_text() { - use termion::color::{Blue, Fg, Green, Reset}; - - let green_hello = format!("{}Hello{} ", Fg(Green), Fg(Reset)); - let blue_world = format!("{}World!{}", Fg(Blue), Fg(Reset)); - assert_iter_eq!( - AsciiSpace.find_words(&format!("{}{}", green_hello, blue_world)), - vec![Word::from(&green_hello), Word::from(&blue_world)] - ); - - #[cfg(feature = "unicode-linebreak")] - assert_iter_eq!( - UnicodeBreakProperties.find_words(&format!("{}{}", green_hello, blue_world)), - vec![Word::from(&green_hello), Word::from(&blue_world)] - ); - } - - #[test] - fn find_words_color_inside_word() { - let text = "foo\u{1b}[0m\u{1b}[32mbar\u{1b}[0mbaz"; - assert_iter_eq!(AsciiSpace.find_words(text), vec![Word::from(text)]); - - #[cfg(feature = "unicode-linebreak")] - assert_iter_eq!( - UnicodeBreakProperties.find_words(text), - vec![Word::from(text)] - ); - } - - #[test] - fn word_separator_new() { - #[cfg(feature = "unicode-linebreak")] - assert!(matches!(WordSeparator::new(), UnicodeBreakProperties)); - - #[cfg(not(feature = "unicode-linebreak"))] - assert!(matches!(WordSeparator::new(), AsciiSpace)); - } -} diff --git a/third_party/rust/textwrap/src/word_splitters.rs b/third_party/rust/textwrap/src/word_splitters.rs deleted file mode 100644 index e2dc6aa01f93..000000000000 --- a/third_party/rust/textwrap/src/word_splitters.rs +++ /dev/null @@ -1,314 +0,0 @@ -//! Word splitting functionality. -//! -//! To wrap text into lines, long words sometimes need to be split -//! across lines. The [`WordSplitter`] enum defines this -//! functionality. - -use crate::core::{display_width, Word}; - -/// The `WordSplitter` enum describes where words can be split. -/// -/// If the textwrap crate has been compiled with the `hyphenation` -/// Cargo feature enabled, you will find a -/// [`WordSplitter::Hyphenation`] variant. Use this struct for -/// language-aware hyphenation: -/// -/// ``` -/// #[cfg(feature = "hyphenation")] { -/// use hyphenation::{Language, Load, Standard}; -/// use textwrap::{wrap, Options, WordSplitter}; -/// -/// let text = "Oxidation is the loss of electrons."; -/// let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); -/// let options = Options::new(8).word_splitter(WordSplitter::Hyphenation(dictionary)); -/// assert_eq!(wrap(text, &options), vec!["Oxida-", -/// "tion is", -/// "the loss", -/// "of elec-", -/// "trons."]); -/// } -/// ``` -/// -/// Please see the documentation for the [hyphenation] crate for more -/// details. -/// -/// [hyphenation]: https://docs.rs/hyphenation/ -#[derive(Clone)] -pub enum WordSplitter { - /// Use this as a [`Options.word_splitter`] to avoid any kind of - /// hyphenation: - /// - /// ``` - /// use textwrap::{wrap, Options, WordSplitter}; - /// - /// let options = Options::new(8).word_splitter(WordSplitter::NoHyphenation); - /// assert_eq!(wrap("foo bar-baz", &options), - /// vec!["foo", "bar-baz"]); - /// ``` - /// - /// [`Options.word_splitter`]: super::Options::word_splitter - NoHyphenation, - - /// `HyphenSplitter` is the default `WordSplitter` used by - /// [`Options::new`](super::Options::new). It will split words on - /// existing hyphens in the word. - /// - /// It will only use hyphens that are surrounded by alphanumeric - /// characters, which prevents a word like `"--foo-bar"` from - /// being split into `"--"` and `"foo-bar"`. - /// - /// # Examples - /// - /// ``` - /// use textwrap::WordSplitter; - /// - /// assert_eq!(WordSplitter::HyphenSplitter.split_points("--foo-bar"), - /// vec![6]); - /// ``` - HyphenSplitter, - - /// Use a custom function as the word splitter. - /// - /// This variant lets you implement a custom word splitter using - /// your own function. - /// - /// # Examples - /// - /// ``` - /// use textwrap::WordSplitter; - /// - /// fn split_at_underscore(word: &str) -> Vec { - /// word.match_indices('_').map(|(idx, _)| idx + 1).collect() - /// } - /// - /// let word_splitter = WordSplitter::Custom(split_at_underscore); - /// assert_eq!(word_splitter.split_points("a_long_identifier"), - /// vec![2, 7]); - /// ``` - Custom(fn(word: &str) -> Vec), - - /// A hyphenation dictionary can be used to do language-specific - /// hyphenation using patterns from the [hyphenation] crate. - /// - /// **Note:** Only available when the `hyphenation` Cargo feature is - /// enabled. - /// - /// [hyphenation]: https://docs.rs/hyphenation/ - #[cfg(feature = "hyphenation")] - Hyphenation(hyphenation::Standard), -} - -impl std::fmt::Debug for WordSplitter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - WordSplitter::NoHyphenation => f.write_str("NoHyphenation"), - WordSplitter::HyphenSplitter => f.write_str("HyphenSplitter"), - WordSplitter::Custom(_) => f.write_str("Custom(...)"), - #[cfg(feature = "hyphenation")] - WordSplitter::Hyphenation(dict) => write!(f, "Hyphenation({})", dict.language()), - } - } -} - -impl PartialEq for WordSplitter { - fn eq(&self, other: &WordSplitter) -> bool { - match (self, other) { - (WordSplitter::NoHyphenation, WordSplitter::NoHyphenation) => true, - (WordSplitter::HyphenSplitter, WordSplitter::HyphenSplitter) => true, - #[cfg(feature = "hyphenation")] - (WordSplitter::Hyphenation(this_dict), WordSplitter::Hyphenation(other_dict)) => { - this_dict.language() == other_dict.language() - } - (_, _) => false, - } - } -} - -impl WordSplitter { - /// Return all possible indices where `word` can be split. - /// - /// The indices are in the range `0..word.len()`. They point to - /// the index _after_ the split point, i.e., after `-` if - /// splitting on hyphens. This way, `word.split_at(idx)` will - /// break the word into two well-formed pieces. - /// - /// # Examples - /// - /// ``` - /// use textwrap::WordSplitter; - /// assert_eq!(WordSplitter::NoHyphenation.split_points("cannot-be-split"), vec![]); - /// assert_eq!(WordSplitter::HyphenSplitter.split_points("can-be-split"), vec![4, 7]); - /// assert_eq!(WordSplitter::Custom(|word| vec![word.len()/2]).split_points("middle"), vec![3]); - /// ``` - pub fn split_points(&self, word: &str) -> Vec { - match self { - WordSplitter::NoHyphenation => Vec::new(), - WordSplitter::HyphenSplitter => { - let mut splits = Vec::new(); - - for (idx, _) in word.match_indices('-') { - // We only use hyphens that are surrounded by alphanumeric - // characters. This is to avoid splitting on repeated hyphens, - // such as those found in --foo-bar. - let prev = word[..idx].chars().next_back(); - let next = word[idx + 1..].chars().next(); - - if prev.filter(|ch| ch.is_alphanumeric()).is_some() - && next.filter(|ch| ch.is_alphanumeric()).is_some() - { - splits.push(idx + 1); // +1 due to width of '-'. - } - } - - splits - } - WordSplitter::Custom(splitter_func) => splitter_func(word), - #[cfg(feature = "hyphenation")] - WordSplitter::Hyphenation(dictionary) => { - use hyphenation::Hyphenator; - dictionary.hyphenate(word).breaks - } - } - } -} - -/// Split words into smaller words according to the split points given -/// by `word_splitter`. -/// -/// Note that we split all words, regardless of their length. This is -/// to more cleanly separate the business of splitting (including -/// automatic hyphenation) from the business of word wrapping. -pub fn split_words<'a, I>( - words: I, - word_splitter: &'a WordSplitter, -) -> impl Iterator> -where - I: IntoIterator>, -{ - words.into_iter().flat_map(move |word| { - let mut prev = 0; - let mut split_points = word_splitter.split_points(&word).into_iter(); - std::iter::from_fn(move || { - if let Some(idx) = split_points.next() { - let need_hyphen = !word[..idx].ends_with('-'); - let w = Word { - word: &word.word[prev..idx], - width: display_width(&word[prev..idx]), - whitespace: "", - penalty: if need_hyphen { "-" } else { "" }, - }; - prev = idx; - return Some(w); - } - - if prev < word.word.len() || prev == 0 { - let w = Word { - word: &word.word[prev..], - width: display_width(&word[prev..]), - whitespace: word.whitespace, - penalty: word.penalty, - }; - prev = word.word.len() + 1; - return Some(w); - } - - None - }) - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - // Like assert_eq!, but the left expression is an iterator. - macro_rules! assert_iter_eq { - ($left:expr, $right:expr) => { - assert_eq!($left.collect::>(), $right); - }; - } - - #[test] - fn split_words_no_words() { - assert_iter_eq!(split_words(vec![], &WordSplitter::HyphenSplitter), vec![]); - } - - #[test] - fn split_words_empty_word() { - assert_iter_eq!( - split_words(vec![Word::from(" ")], &WordSplitter::HyphenSplitter), - vec![Word::from(" ")] - ); - } - - #[test] - fn split_words_single_word() { - assert_iter_eq!( - split_words(vec![Word::from("foobar")], &WordSplitter::HyphenSplitter), - vec![Word::from("foobar")] - ); - } - - #[test] - fn split_words_hyphen_splitter() { - assert_iter_eq!( - split_words(vec![Word::from("foo-bar")], &WordSplitter::HyphenSplitter), - vec![Word::from("foo-"), Word::from("bar")] - ); - } - - #[test] - fn split_words_no_hyphenation() { - assert_iter_eq!( - split_words(vec![Word::from("foo-bar")], &WordSplitter::NoHyphenation), - vec![Word::from("foo-bar")] - ); - } - - #[test] - fn split_words_adds_penalty() { - let fixed_split_point = |_: &str| vec![3]; - - assert_iter_eq!( - split_words( - vec![Word::from("foobar")].into_iter(), - &WordSplitter::Custom(fixed_split_point) - ), - vec![ - Word { - word: "foo", - width: 3, - whitespace: "", - penalty: "-" - }, - Word { - word: "bar", - width: 3, - whitespace: "", - penalty: "" - } - ] - ); - - assert_iter_eq!( - split_words( - vec![Word::from("fo-bar")].into_iter(), - &WordSplitter::Custom(fixed_split_point) - ), - vec![ - Word { - word: "fo-", - width: 3, - whitespace: "", - penalty: "" - }, - Word { - word: "bar", - width: 3, - whitespace: "", - penalty: "" - } - ] - ); - } -} diff --git a/third_party/rust/textwrap/src/wrap.rs b/third_party/rust/textwrap/src/wrap.rs deleted file mode 100644 index a7f2ccf29846..000000000000 --- a/third_party/rust/textwrap/src/wrap.rs +++ /dev/null @@ -1,686 +0,0 @@ -//! Functions for wrapping text. - -use std::borrow::Cow; - -use crate::core::{break_words, display_width, Word}; -use crate::word_splitters::split_words; -use crate::Options; - -/// Wrap a line of text at a given width. -/// -/// The result is a vector of lines, each line is of type [`Cow<'_, -/// str>`](Cow), which means that the line will borrow from the input -/// `&str` if possible. The lines do not have trailing whitespace, -/// including a final `'\n'`. Please use [`fill()`](crate::fill()) if -/// you need a [`String`] instead. -/// -/// The easiest way to use this function is to pass an integer for -/// `width_or_options`: -/// -/// ``` -/// use textwrap::wrap; -/// -/// let lines = wrap("Memory safety without garbage collection.", 15); -/// assert_eq!(lines, &[ -/// "Memory safety", -/// "without garbage", -/// "collection.", -/// ]); -/// ``` -/// -/// If you need to customize the wrapping, you can pass an [`Options`] -/// instead of an `usize`: -/// -/// ``` -/// use textwrap::{wrap, Options}; -/// -/// let options = Options::new(15) -/// .initial_indent("- ") -/// .subsequent_indent(" "); -/// let lines = wrap("Memory safety without garbage collection.", &options); -/// assert_eq!(lines, &[ -/// "- Memory safety", -/// " without", -/// " garbage", -/// " collection.", -/// ]); -/// ``` -/// -/// # Optimal-Fit Wrapping -/// -/// By default, `wrap` will try to ensure an even right margin by -/// finding breaks which avoid short lines. We call this an -/// “optimal-fit algorithm” since the line breaks are computed by -/// considering all possible line breaks. The alternative is a -/// “first-fit algorithm” which simply accumulates words until they no -/// longer fit on the line. -/// -/// As an example, using the first-fit algorithm to wrap the famous -/// Hamlet quote “To be, or not to be: that is the question” in a -/// narrow column with room for only 10 characters looks like this: -/// -/// ``` -/// # use textwrap::{WrapAlgorithm::FirstFit, Options, wrap}; -/// # -/// # let lines = wrap("To be, or not to be: that is the question", -/// # Options::new(10).wrap_algorithm(FirstFit)); -/// # assert_eq!(lines.join("\n") + "\n", "\ -/// To be, or -/// not to be: -/// that is -/// the -/// question -/// # "); -/// ``` -/// -/// Notice how the second to last line is quite narrow because -/// “question” was too large to fit? The greedy first-fit algorithm -/// doesn’t look ahead, so it has no other option than to put -/// “question” onto its own line. -/// -/// With the optimal-fit wrapping algorithm, the previous lines are -/// shortened slightly in order to make the word “is” go into the -/// second last line: -/// -/// ``` -/// # #[cfg(feature = "smawk")] { -/// # use textwrap::{Options, WrapAlgorithm, wrap}; -/// # -/// # let lines = wrap( -/// # "To be, or not to be: that is the question", -/// # Options::new(10).wrap_algorithm(WrapAlgorithm::new_optimal_fit()) -/// # ); -/// # assert_eq!(lines.join("\n") + "\n", "\ -/// To be, -/// or not to -/// be: that -/// is the -/// question -/// # "); } -/// ``` -/// -/// Please see [`WrapAlgorithm`](crate::WrapAlgorithm) for details on -/// the choices. -/// -/// # Examples -/// -/// The returned iterator yields lines of type `Cow<'_, str>`. If -/// possible, the wrapped lines will borrow from the input string. As -/// an example, a hanging indentation, the first line can borrow from -/// the input, but the subsequent lines become owned strings: -/// -/// ``` -/// use std::borrow::Cow::{Borrowed, Owned}; -/// use textwrap::{wrap, Options}; -/// -/// let options = Options::new(15).subsequent_indent("...."); -/// let lines = wrap("Wrapping text all day long.", &options); -/// let annotated = lines -/// .iter() -/// .map(|line| match line { -/// Borrowed(text) => format!("[Borrowed] {}", text), -/// Owned(text) => format!("[Owned] {}", text), -/// }) -/// .collect::>(); -/// assert_eq!( -/// annotated, -/// &[ -/// "[Borrowed] Wrapping text", -/// "[Owned] ....all day", -/// "[Owned] ....long.", -/// ] -/// ); -/// ``` -/// -/// ## Leading and Trailing Whitespace -/// -/// As a rule, leading whitespace (indentation) is preserved and -/// trailing whitespace is discarded. -/// -/// In more details, when wrapping words into lines, words are found -/// by splitting the input text on space characters. One or more -/// spaces (shown here as “␣”) are attached to the end of each word: -/// -/// ```text -/// "Foo␣␣␣bar␣baz" -> ["Foo␣␣␣", "bar␣", "baz"] -/// ``` -/// -/// These words are then put into lines. The interword whitespace is -/// preserved, unless the lines are wrapped so that the `"Foo␣␣␣"` -/// word falls at the end of a line: -/// -/// ``` -/// use textwrap::wrap; -/// -/// assert_eq!(wrap("Foo bar baz", 10), vec!["Foo bar", "baz"]); -/// assert_eq!(wrap("Foo bar baz", 8), vec!["Foo", "bar baz"]); -/// ``` -/// -/// Notice how the trailing whitespace is removed in both case: in the -/// first example, `"bar␣"` becomes `"bar"` and in the second case -/// `"Foo␣␣␣"` becomes `"Foo"`. -/// -/// Leading whitespace is preserved when the following word fits on -/// the first line. To understand this, consider how words are found -/// in a text with leading spaces: -/// -/// ```text -/// "␣␣foo␣bar" -> ["␣␣", "foo␣", "bar"] -/// ``` -/// -/// When put into lines, the indentation is preserved if `"foo"` fits -/// on the first line, otherwise you end up with an empty line: -/// -/// ``` -/// use textwrap::wrap; -/// -/// assert_eq!(wrap(" foo bar", 8), vec![" foo", "bar"]); -/// assert_eq!(wrap(" foo bar", 4), vec!["", "foo", "bar"]); -/// ``` -pub fn wrap<'a, Opt>(text: &str, width_or_options: Opt) -> Vec> -where - Opt: Into>, -{ - let options: Options = width_or_options.into(); - let line_ending_str = options.line_ending.as_str(); - - let mut lines = Vec::new(); - for line in text.split(line_ending_str) { - wrap_single_line(line, &options, &mut lines); - } - - lines -} - -pub(crate) fn wrap_single_line<'a>( - line: &'a str, - options: &Options<'_>, - lines: &mut Vec>, -) { - let indent = if lines.is_empty() { - options.initial_indent - } else { - options.subsequent_indent - }; - if line.len() < options.width && indent.is_empty() { - lines.push(Cow::from(line.trim_end_matches(' '))); - } else { - wrap_single_line_slow_path(line, options, lines) - } -} - -/// Wrap a single line of text. -/// -/// This is taken when `line` is longer than `options.width`. -pub(crate) fn wrap_single_line_slow_path<'a>( - line: &'a str, - options: &Options<'_>, - lines: &mut Vec>, -) { - let initial_width = options - .width - .saturating_sub(display_width(options.initial_indent)); - let subsequent_width = options - .width - .saturating_sub(display_width(options.subsequent_indent)); - let line_widths = [initial_width, subsequent_width]; - - let words = options.word_separator.find_words(line); - let split_words = split_words(words, &options.word_splitter); - let broken_words = if options.break_words { - let mut broken_words = break_words(split_words, line_widths[1]); - if !options.initial_indent.is_empty() { - // Without this, the first word will always go into the - // first line. However, since we break words based on the - // _second_ line width, it can be wrong to unconditionally - // put the first word onto the first line. An empty - // zero-width word fixed this. - broken_words.insert(0, Word::from("")); - } - broken_words - } else { - split_words.collect::>() - }; - - let wrapped_words = options.wrap_algorithm.wrap(&broken_words, &line_widths); - - let mut idx = 0; - for words in wrapped_words { - let last_word = match words.last() { - None => { - lines.push(Cow::from("")); - continue; - } - Some(word) => word, - }; - - // We assume here that all words are contiguous in `line`. - // That is, the sum of their lengths should add up to the - // length of `line`. - let len = words - .iter() - .map(|word| word.len() + word.whitespace.len()) - .sum::() - - last_word.whitespace.len(); - - // The result is owned if we have indentation, otherwise we - // can simply borrow an empty string. - let mut result = if lines.is_empty() && !options.initial_indent.is_empty() { - Cow::Owned(options.initial_indent.to_owned()) - } else if !lines.is_empty() && !options.subsequent_indent.is_empty() { - Cow::Owned(options.subsequent_indent.to_owned()) - } else { - // We can use an empty string here since string - // concatenation for `Cow` preserves a borrowed value when - // either side is empty. - Cow::from("") - }; - - result += &line[idx..idx + len]; - - if !last_word.penalty.is_empty() { - result.to_mut().push_str(last_word.penalty); - } - - lines.push(result); - - // Advance by the length of `result`, plus the length of - // `last_word.whitespace` -- even if we had a penalty, we need - // to skip over the whitespace. - idx += len + last_word.whitespace.len(); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{WordSeparator, WordSplitter, WrapAlgorithm}; - - #[cfg(feature = "hyphenation")] - use hyphenation::{Language, Load, Standard}; - - #[test] - fn no_wrap() { - assert_eq!(wrap("foo", 10), vec!["foo"]); - } - - #[test] - fn wrap_simple() { - assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]); - } - - #[test] - fn to_be_or_not() { - assert_eq!( - wrap( - "To be, or not to be, that is the question.", - Options::new(10).wrap_algorithm(WrapAlgorithm::FirstFit) - ), - vec!["To be, or", "not to be,", "that is", "the", "question."] - ); - } - - #[test] - fn multiple_words_on_first_line() { - assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]); - } - - #[test] - fn long_word() { - assert_eq!(wrap("foo", 0), vec!["f", "o", "o"]); - } - - #[test] - fn long_words() { - assert_eq!(wrap("foo bar", 0), vec!["f", "o", "o", "b", "a", "r"]); - } - - #[test] - fn max_width() { - assert_eq!(wrap("foo bar", usize::MAX), vec!["foo bar"]); - - let text = "Hello there! This is some English text. \ - It should not be wrapped given the extents below."; - assert_eq!(wrap(text, usize::MAX), vec![text]); - } - - #[test] - fn leading_whitespace() { - assert_eq!(wrap(" foo bar", 6), vec![" foo", "bar"]); - } - - #[test] - fn leading_whitespace_empty_first_line() { - // If there is no space for the first word, the first line - // will be empty. This is because the string is split into - // words like [" ", "foobar ", "baz"], which puts "foobar " on - // the second line. We never output trailing whitespace - assert_eq!(wrap(" foobar baz", 6), vec!["", "foobar", "baz"]); - } - - #[test] - fn trailing_whitespace() { - // Whitespace is only significant inside a line. After a line - // gets too long and is broken, the first word starts in - // column zero and is not indented. - assert_eq!(wrap("foo bar baz ", 5), vec!["foo", "bar", "baz"]); - } - - #[test] - fn issue_99() { - // We did not reset the in_whitespace flag correctly and did - // not handle single-character words after a line break. - assert_eq!( - wrap("aaabbbccc x yyyzzzwww", 9), - vec!["aaabbbccc", "x", "yyyzzzwww"] - ); - } - - #[test] - fn issue_129() { - // The dash is an em-dash which takes up four bytes. We used - // to panic since we tried to index into the character. - let options = Options::new(1).word_separator(WordSeparator::AsciiSpace); - assert_eq!(wrap("x – x", options), vec!["x", "–", "x"]); - } - - #[test] - fn wide_character_handling() { - assert_eq!(wrap("Hello, World!", 15), vec!["Hello, World!"]); - assert_eq!( - wrap( - "Hello, World!", - Options::new(15).word_separator(WordSeparator::AsciiSpace) - ), - vec!["Hello,", "World!"] - ); - - // Wide characters are allowed to break if the - // unicode-linebreak feature is enabled. - #[cfg(feature = "unicode-linebreak")] - assert_eq!( - wrap( - "Hello, World!", - Options::new(15).word_separator(WordSeparator::UnicodeBreakProperties), - ), - vec!["Hello, W", "orld!"] - ); - } - - #[test] - fn indent_empty_line() { - // Previously, indentation was not applied to empty lines. - // However, this is somewhat inconsistent and undesirable if - // the indentation is something like a border ("| ") which you - // want to apply to all lines, empty or not. - let options = Options::new(10).initial_indent("!!!"); - assert_eq!(wrap("", &options), vec!["!!!"]); - } - - #[test] - fn indent_single_line() { - let options = Options::new(10).initial_indent(">>>"); // No trailing space - assert_eq!(wrap("foo", &options), vec![">>>foo"]); - } - - #[test] - fn indent_first_emoji() { - let options = Options::new(10).initial_indent("👉👉"); - assert_eq!( - wrap("x x x x x x x x x x x x x", &options), - vec!["👉👉x x x", "x x x x x", "x x x x x"] - ); - } - - #[test] - fn indent_multiple_lines() { - let options = Options::new(6).initial_indent("* ").subsequent_indent(" "); - assert_eq!( - wrap("foo bar baz", &options), - vec!["* foo", " bar", " baz"] - ); - } - - #[test] - fn only_initial_indent_multiple_lines() { - let options = Options::new(10).initial_indent(" "); - assert_eq!(wrap("foo\nbar\nbaz", &options), vec![" foo", "bar", "baz"]); - } - - #[test] - fn only_subsequent_indent_multiple_lines() { - let options = Options::new(10).subsequent_indent(" "); - assert_eq!( - wrap("foo\nbar\nbaz", &options), - vec!["foo", " bar", " baz"] - ); - } - - #[test] - fn indent_break_words() { - let options = Options::new(5).initial_indent("* ").subsequent_indent(" "); - assert_eq!(wrap("foobarbaz", &options), vec!["* foo", " bar", " baz"]); - } - - #[test] - fn initial_indent_break_words() { - // This is a corner-case showing how the long word is broken - // according to the width of the subsequent lines. The first - // fragment of the word no longer fits on the first line, - // which ends up being pure indentation. - let options = Options::new(5).initial_indent("-->"); - assert_eq!(wrap("foobarbaz", &options), vec!["-->", "fooba", "rbaz"]); - } - - #[test] - fn hyphens() { - assert_eq!(wrap("foo-bar", 5), vec!["foo-", "bar"]); - } - - #[test] - fn trailing_hyphen() { - let options = Options::new(5).break_words(false); - assert_eq!(wrap("foobar-", &options), vec!["foobar-"]); - } - - #[test] - fn multiple_hyphens() { - assert_eq!(wrap("foo-bar-baz", 5), vec!["foo-", "bar-", "baz"]); - } - - #[test] - fn hyphens_flag() { - let options = Options::new(5).break_words(false); - assert_eq!( - wrap("The --foo-bar flag.", &options), - vec!["The", "--foo-", "bar", "flag."] - ); - } - - #[test] - fn repeated_hyphens() { - let options = Options::new(4).break_words(false); - assert_eq!(wrap("foo--bar", &options), vec!["foo--bar"]); - } - - #[test] - fn hyphens_alphanumeric() { - assert_eq!(wrap("Na2-CH4", 5), vec!["Na2-", "CH4"]); - } - - #[test] - fn hyphens_non_alphanumeric() { - let options = Options::new(5).break_words(false); - assert_eq!(wrap("foo(-)bar", &options), vec!["foo(-)bar"]); - } - - #[test] - fn multiple_splits() { - assert_eq!(wrap("foo-bar-baz", 9), vec!["foo-bar-", "baz"]); - } - - #[test] - fn forced_split() { - let options = Options::new(5).break_words(false); - assert_eq!(wrap("foobar-baz", &options), vec!["foobar-", "baz"]); - } - - #[test] - fn multiple_unbroken_words_issue_193() { - let options = Options::new(3).break_words(false); - assert_eq!( - wrap("small large tiny", &options), - vec!["small", "large", "tiny"] - ); - assert_eq!( - wrap("small large tiny", &options), - vec!["small", "large", "tiny"] - ); - } - - #[test] - fn very_narrow_lines_issue_193() { - let options = Options::new(1).break_words(false); - assert_eq!(wrap("fooo x y", &options), vec!["fooo", "x", "y"]); - assert_eq!(wrap("fooo x y", &options), vec!["fooo", "x", "y"]); - } - - #[test] - fn simple_hyphens() { - let options = Options::new(8).word_splitter(WordSplitter::HyphenSplitter); - assert_eq!(wrap("foo bar-baz", &options), vec!["foo bar-", "baz"]); - } - - #[test] - fn no_hyphenation() { - let options = Options::new(8).word_splitter(WordSplitter::NoHyphenation); - assert_eq!(wrap("foo bar-baz", &options), vec!["foo", "bar-baz"]); - } - - #[test] - #[cfg(feature = "hyphenation")] - fn auto_hyphenation_double_hyphenation() { - let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); - let options = Options::new(10); - assert_eq!( - wrap("Internationalization", &options), - vec!["Internatio", "nalization"] - ); - - let options = Options::new(10).word_splitter(WordSplitter::Hyphenation(dictionary)); - assert_eq!( - wrap("Internationalization", &options), - vec!["Interna-", "tionaliza-", "tion"] - ); - } - - #[test] - #[cfg(feature = "hyphenation")] - fn auto_hyphenation_issue_158() { - let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); - let options = Options::new(10); - assert_eq!( - wrap("participation is the key to success", &options), - vec!["participat", "ion is", "the key to", "success"] - ); - - let options = Options::new(10).word_splitter(WordSplitter::Hyphenation(dictionary)); - assert_eq!( - wrap("participation is the key to success", &options), - vec!["partici-", "pation is", "the key to", "success"] - ); - } - - #[test] - #[cfg(feature = "hyphenation")] - fn split_len_hyphenation() { - // Test that hyphenation takes the width of the whitespace - // into account. - let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); - let options = Options::new(15).word_splitter(WordSplitter::Hyphenation(dictionary)); - assert_eq!( - wrap("garbage collection", &options), - vec!["garbage col-", "lection"] - ); - } - - #[test] - #[cfg(feature = "hyphenation")] - fn borrowed_lines() { - // Lines that end with an extra hyphen are owned, the final - // line is borrowed. - use std::borrow::Cow::{Borrowed, Owned}; - let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); - let options = Options::new(10).word_splitter(WordSplitter::Hyphenation(dictionary)); - let lines = wrap("Internationalization", &options); - assert_eq!(lines, vec!["Interna-", "tionaliza-", "tion"]); - if let Borrowed(s) = lines[0] { - assert!(false, "should not have been borrowed: {:?}", s); - } - if let Borrowed(s) = lines[1] { - assert!(false, "should not have been borrowed: {:?}", s); - } - if let Owned(ref s) = lines[2] { - assert!(false, "should not have been owned: {:?}", s); - } - } - - #[test] - #[cfg(feature = "hyphenation")] - fn auto_hyphenation_with_hyphen() { - let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap(); - let options = Options::new(8).break_words(false); - assert_eq!( - wrap("over-caffinated", &options), - vec!["over-", "caffinated"] - ); - - let options = options.word_splitter(WordSplitter::Hyphenation(dictionary)); - assert_eq!( - wrap("over-caffinated", &options), - vec!["over-", "caffi-", "nated"] - ); - } - - #[test] - fn break_words() { - assert_eq!(wrap("foobarbaz", 3), vec!["foo", "bar", "baz"]); - } - - #[test] - fn break_words_wide_characters() { - // Even the poor man's version of `ch_width` counts these - // characters as wide. - let options = Options::new(5).word_separator(WordSeparator::AsciiSpace); - assert_eq!(wrap("Hello", options), vec!["He", "ll", "o"]); - } - - #[test] - fn break_words_zero_width() { - assert_eq!(wrap("foobar", 0), vec!["f", "o", "o", "b", "a", "r"]); - } - - #[test] - fn break_long_first_word() { - assert_eq!(wrap("testx y", 4), vec!["test", "x y"]); - } - - #[test] - fn wrap_preserves_line_breaks_trims_whitespace() { - assert_eq!(wrap(" ", 80), vec![""]); - assert_eq!(wrap(" \n ", 80), vec!["", ""]); - assert_eq!(wrap(" \n \n \n ", 80), vec!["", "", "", ""]); - } - - #[test] - fn wrap_colored_text() { - // The words are much longer than 6 bytes, but they remain - // intact after filling the text. - let green_hello = "\u{1b}[0m\u{1b}[32mHello\u{1b}[0m"; - let blue_world = "\u{1b}[0m\u{1b}[34mWorld!\u{1b}[0m"; - assert_eq!( - wrap(&format!("{} {}", green_hello, blue_world), 6), - vec![green_hello, blue_world], - ); - } -} diff --git a/third_party/rust/textwrap/src/wrap_algorithms.rs b/third_party/rust/textwrap/src/wrap_algorithms.rs deleted file mode 100644 index 7737e08f9954..000000000000 --- a/third_party/rust/textwrap/src/wrap_algorithms.rs +++ /dev/null @@ -1,413 +0,0 @@ -//! Word wrapping algorithms. -//! -//! After a text has been broken into words (or [`Fragment`]s), one -//! now has to decide how to break the fragments into lines. The -//! simplest algorithm for this is implemented by -//! [`wrap_first_fit()`]: it uses no look-ahead and simply adds -//! fragments to the line as long as they fit. However, this can lead -//! to poor line breaks if a large fragment almost-but-not-quite fits -//! on a line. When that happens, the fragment is moved to the next -//! line and it will leave behind a large gap. -//! -//! A more advanced algorithm, implemented by [`wrap_optimal_fit()`], -//! will take this into account. The optimal-fit algorithm considers -//! all possible line breaks and will attempt to minimize the gaps -//! left behind by overly short lines. -//! -//! While both algorithms run in linear time, the first-fit algorithm -//! is about 4 times faster than the optimal-fit algorithm. - -#[cfg(feature = "smawk")] -mod optimal_fit; -#[cfg(feature = "smawk")] -pub use optimal_fit::{wrap_optimal_fit, OverflowError, Penalties}; - -use crate::core::{Fragment, Word}; - -/// Describes how to wrap words into lines. -/// -/// The simplest approach is to wrap words one word at a time and -/// accept the first way of wrapping which fit -/// ([`WrapAlgorithm::FirstFit`]). If the `smawk` Cargo feature is -/// enabled, a more complex algorithm is available which will look at -/// an entire paragraph at a time in order to find optimal line breaks -/// ([`WrapAlgorithm::OptimalFit`]). -#[derive(Clone, Copy)] -pub enum WrapAlgorithm { - /// Wrap words using a fast and simple algorithm. - /// - /// This algorithm uses no look-ahead when finding line breaks. - /// Implemented by [`wrap_first_fit()`], please see that function - /// for details and examples. - FirstFit, - - /// Wrap words using an advanced algorithm with look-ahead. - /// - /// This wrapping algorithm considers the entire paragraph to find - /// optimal line breaks. When wrapping text, "penalties" are - /// assigned to line breaks based on the gaps left at the end of - /// lines. See [`Penalties`] for details. - /// - /// The underlying wrapping algorithm is implemented by - /// [`wrap_optimal_fit()`], please see that function for examples. - /// - /// **Note:** Only available when the `smawk` Cargo feature is - /// enabled. - #[cfg(feature = "smawk")] - OptimalFit(Penalties), - - /// Custom wrapping function. - /// - /// Use this if you want to implement your own wrapping algorithm. - /// The function can freely decide how to turn a slice of - /// [`Word`]s into lines. - /// - /// # Example - /// - /// ``` - /// use textwrap::core::Word; - /// use textwrap::{wrap, Options, WrapAlgorithm}; - /// - /// fn stair<'a, 'b>(words: &'b [Word<'a>], _: &'b [usize]) -> Vec<&'b [Word<'a>]> { - /// let mut lines = Vec::new(); - /// let mut step = 1; - /// let mut start_idx = 0; - /// while start_idx + step <= words.len() { - /// lines.push(&words[start_idx .. start_idx+step]); - /// start_idx += step; - /// step += 1; - /// } - /// lines - /// } - /// - /// let options = Options::new(10).wrap_algorithm(WrapAlgorithm::Custom(stair)); - /// assert_eq!(wrap("First, second, third, fourth, fifth, sixth", options), - /// vec!["First,", - /// "second, third,", - /// "fourth, fifth, sixth"]); - /// ``` - Custom(for<'a, 'b> fn(words: &'b [Word<'a>], line_widths: &'b [usize]) -> Vec<&'b [Word<'a>]>), -} - -impl PartialEq for WrapAlgorithm { - /// Compare two wrap algorithms. - /// - /// ``` - /// use textwrap::WrapAlgorithm; - /// - /// assert_eq!(WrapAlgorithm::FirstFit, WrapAlgorithm::FirstFit); - /// #[cfg(feature = "smawk")] { - /// assert_eq!(WrapAlgorithm::new_optimal_fit(), WrapAlgorithm::new_optimal_fit()); - /// } - /// ``` - /// - /// Note that `WrapAlgorithm::Custom` values never compare equal: - /// - /// ``` - /// use textwrap::WrapAlgorithm; - /// - /// assert_ne!(WrapAlgorithm::Custom(|words, line_widths| vec![words]), - /// WrapAlgorithm::Custom(|words, line_widths| vec![words])); - /// ``` - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (WrapAlgorithm::FirstFit, WrapAlgorithm::FirstFit) => true, - #[cfg(feature = "smawk")] - (WrapAlgorithm::OptimalFit(a), WrapAlgorithm::OptimalFit(b)) => a == b, - (_, _) => false, - } - } -} - -impl std::fmt::Debug for WrapAlgorithm { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - WrapAlgorithm::FirstFit => f.write_str("FirstFit"), - #[cfg(feature = "smawk")] - WrapAlgorithm::OptimalFit(penalties) => write!(f, "OptimalFit({:?})", penalties), - WrapAlgorithm::Custom(_) => f.write_str("Custom(...)"), - } - } -} - -impl WrapAlgorithm { - /// Create new wrap algorithm. - /// - /// The best wrapping algorithm is used by default, i.e., - /// [`WrapAlgorithm::OptimalFit`] if available, otherwise - /// [`WrapAlgorithm::FirstFit`]. - pub const fn new() -> Self { - #[cfg(not(feature = "smawk"))] - { - WrapAlgorithm::FirstFit - } - - #[cfg(feature = "smawk")] - { - WrapAlgorithm::new_optimal_fit() - } - } - - /// New [`WrapAlgorithm::OptimalFit`] with default penalties. This - /// works well for monospace text. - /// - /// **Note:** Only available when the `smawk` Cargo feature is - /// enabled. - #[cfg(feature = "smawk")] - pub const fn new_optimal_fit() -> Self { - WrapAlgorithm::OptimalFit(Penalties::new()) - } - - /// Wrap words according to line widths. - /// - /// The `line_widths` slice gives the target line width for each - /// line (the last slice element is repeated as necessary). This - /// can be used to implement hanging indentation. - #[inline] - pub fn wrap<'a, 'b>( - &self, - words: &'b [Word<'a>], - line_widths: &'b [usize], - ) -> Vec<&'b [Word<'a>]> { - // Every integer up to 2u64.pow(f64::MANTISSA_DIGITS) = 2**53 - // = 9_007_199_254_740_992 can be represented without loss by - // a f64. Larger line widths will be rounded to the nearest - // representable number. - let f64_line_widths = line_widths.iter().map(|w| *w as f64).collect::>(); - - match self { - WrapAlgorithm::FirstFit => wrap_first_fit(words, &f64_line_widths), - - #[cfg(feature = "smawk")] - WrapAlgorithm::OptimalFit(penalties) => { - // The computation cannot overflow when the line - // widths are restricted to usize. - wrap_optimal_fit(words, &f64_line_widths, penalties).unwrap() - } - - WrapAlgorithm::Custom(func) => func(words, line_widths), - } - } -} - -impl Default for WrapAlgorithm { - fn default() -> Self { - WrapAlgorithm::new() - } -} - -/// Wrap abstract fragments into lines with a first-fit algorithm. -/// -/// The `line_widths` slice gives the target line width for each line -/// (the last slice element is repeated as necessary). This can be -/// used to implement hanging indentation. -/// -/// The fragments must already have been split into the desired -/// widths, this function will not (and cannot) attempt to split them -/// further when arranging them into lines. -/// -/// # First-Fit Algorithm -/// -/// This implements a simple “greedy” algorithm: accumulate fragments -/// one by one and when a fragment no longer fits, start a new line. -/// There is no look-ahead, we simply take first fit of the fragments -/// we find. -/// -/// While fast and predictable, this algorithm can produce poor line -/// breaks when a long fragment is moved to a new line, leaving behind -/// a large gap: -/// -/// ``` -/// use textwrap::core::Word; -/// use textwrap::wrap_algorithms::wrap_first_fit; -/// use textwrap::WordSeparator; -/// -/// // Helper to convert wrapped lines to a Vec. -/// fn lines_to_strings(lines: Vec<&[Word<'_>]>) -> Vec { -/// lines.iter().map(|line| { -/// line.iter().map(|word| &**word).collect::>().join(" ") -/// }).collect::>() -/// } -/// -/// let text = "These few words will unfortunately not wrap nicely."; -/// let words = WordSeparator::AsciiSpace.find_words(text).collect::>(); -/// assert_eq!(lines_to_strings(wrap_first_fit(&words, &[15.0])), -/// vec!["These few words", -/// "will", // <-- short line -/// "unfortunately", -/// "not wrap", -/// "nicely."]); -/// -/// // We can avoid the short line if we look ahead: -/// #[cfg(feature = "smawk")] -/// use textwrap::wrap_algorithms::{wrap_optimal_fit, Penalties}; -/// #[cfg(feature = "smawk")] -/// assert_eq!(lines_to_strings(wrap_optimal_fit(&words, &[15.0], &Penalties::new()).unwrap()), -/// vec!["These few", -/// "words will", -/// "unfortunately", -/// "not wrap", -/// "nicely."]); -/// ``` -/// -/// The [`wrap_optimal_fit()`] function was used above to get better -/// line breaks. It uses an advanced algorithm which tries to avoid -/// short lines. This function is about 4 times faster than -/// [`wrap_optimal_fit()`]. -/// -/// # Examples -/// -/// Imagine you're building a house site and you have a number of -/// tasks you need to execute. Things like pour foundation, complete -/// framing, install plumbing, electric cabling, install insulation. -/// -/// The construction workers can only work during daytime, so they -/// need to pack up everything at night. Because they need to secure -/// their tools and move machines back to the garage, this process -/// takes much more time than the time it would take them to simply -/// switch to another task. -/// -/// You would like to make a list of tasks to execute every day based -/// on your estimates. You can model this with a program like this: -/// -/// ``` -/// use textwrap::core::{Fragment, Word}; -/// use textwrap::wrap_algorithms::wrap_first_fit; -/// -/// #[derive(Debug)] -/// struct Task<'a> { -/// name: &'a str, -/// hours: f64, // Time needed to complete task. -/// sweep: f64, // Time needed for a quick sweep after task during the day. -/// cleanup: f64, // Time needed for full cleanup if day ends with this task. -/// } -/// -/// impl Fragment for Task<'_> { -/// fn width(&self) -> f64 { self.hours } -/// fn whitespace_width(&self) -> f64 { self.sweep } -/// fn penalty_width(&self) -> f64 { self.cleanup } -/// } -/// -/// // The morning tasks -/// let tasks = vec![ -/// Task { name: "Foundation", hours: 4.0, sweep: 2.0, cleanup: 3.0 }, -/// Task { name: "Framing", hours: 3.0, sweep: 1.0, cleanup: 2.0 }, -/// Task { name: "Plumbing", hours: 2.0, sweep: 2.0, cleanup: 2.0 }, -/// Task { name: "Electrical", hours: 2.0, sweep: 1.0, cleanup: 2.0 }, -/// Task { name: "Insulation", hours: 2.0, sweep: 1.0, cleanup: 2.0 }, -/// Task { name: "Drywall", hours: 3.0, sweep: 1.0, cleanup: 2.0 }, -/// Task { name: "Floors", hours: 3.0, sweep: 1.0, cleanup: 2.0 }, -/// Task { name: "Countertops", hours: 1.0, sweep: 1.0, cleanup: 2.0 }, -/// Task { name: "Bathrooms", hours: 2.0, sweep: 1.0, cleanup: 2.0 }, -/// ]; -/// -/// // Fill tasks into days, taking `day_length` into account. The -/// // output shows the hours worked per day along with the names of -/// // the tasks for that day. -/// fn assign_days<'a>(tasks: &[Task<'a>], day_length: f64) -> Vec<(f64, Vec<&'a str>)> { -/// let mut days = Vec::new(); -/// // Assign tasks to days. The assignment is a vector of slices, -/// // with a slice per day. -/// let assigned_days: Vec<&[Task<'a>]> = wrap_first_fit(&tasks, &[day_length]); -/// for day in assigned_days.iter() { -/// let last = day.last().unwrap(); -/// let work_hours: f64 = day.iter().map(|t| t.hours + t.sweep).sum(); -/// let names = day.iter().map(|t| t.name).collect::>(); -/// days.push((work_hours - last.sweep + last.cleanup, names)); -/// } -/// days -/// } -/// -/// // With a single crew working 8 hours a day: -/// assert_eq!( -/// assign_days(&tasks, 8.0), -/// [ -/// (7.0, vec!["Foundation"]), -/// (8.0, vec!["Framing", "Plumbing"]), -/// (7.0, vec!["Electrical", "Insulation"]), -/// (5.0, vec!["Drywall"]), -/// (7.0, vec!["Floors", "Countertops"]), -/// (4.0, vec!["Bathrooms"]), -/// ] -/// ); -/// -/// // With two crews working in shifts, 16 hours a day: -/// assert_eq!( -/// assign_days(&tasks, 16.0), -/// [ -/// (14.0, vec!["Foundation", "Framing", "Plumbing"]), -/// (15.0, vec!["Electrical", "Insulation", "Drywall", "Floors"]), -/// (6.0, vec!["Countertops", "Bathrooms"]), -/// ] -/// ); -/// ``` -/// -/// Apologies to anyone who actually knows how to build a house and -/// knows how long each step takes :-) -pub fn wrap_first_fit<'a, T: Fragment>( - fragments: &'a [T], - line_widths: &[f64], -) -> Vec<&'a [T]> { - // The final line width is used for all remaining lines. - let default_line_width = line_widths.last().copied().unwrap_or(0.0); - let mut lines = Vec::new(); - let mut start = 0; - let mut width = 0.0; - - for (idx, fragment) in fragments.iter().enumerate() { - let line_width = line_widths - .get(lines.len()) - .copied() - .unwrap_or(default_line_width); - if width + fragment.width() + fragment.penalty_width() > line_width && idx > start { - lines.push(&fragments[start..idx]); - start = idx; - width = 0.0; - } - width += fragment.width() + fragment.whitespace_width(); - } - lines.push(&fragments[start..]); - lines -} - -#[cfg(test)] -mod tests { - use super::*; - - #[derive(Debug, PartialEq)] - struct Word(f64); - - #[rustfmt::skip] - impl Fragment for Word { - fn width(&self) -> f64 { self.0 } - fn whitespace_width(&self) -> f64 { 1.0 } - fn penalty_width(&self) -> f64 { 0.0 } - } - - #[test] - fn wrap_string_longer_than_f64() { - let words = vec![ - Word(1e307), - Word(2e307), - Word(3e307), - Word(4e307), - Word(5e307), - Word(6e307), - ]; - // Wrap at just under f64::MAX (~19e307). The tiny - // whitespace_widths disappear because of loss of precision. - assert_eq!( - wrap_first_fit(&words, &[15e307]), - &[ - vec![ - Word(1e307), - Word(2e307), - Word(3e307), - Word(4e307), - Word(5e307) - ], - vec![Word(6e307)] - ] - ); - } -} diff --git a/third_party/rust/textwrap/src/wrap_algorithms/optimal_fit.rs b/third_party/rust/textwrap/src/wrap_algorithms/optimal_fit.rs deleted file mode 100644 index bdc0334539ee..000000000000 --- a/third_party/rust/textwrap/src/wrap_algorithms/optimal_fit.rs +++ /dev/null @@ -1,433 +0,0 @@ -use std::cell::RefCell; - -use crate::core::Fragment; - -/// Penalties for -/// [`WrapAlgorithm::OptimalFit`](crate::WrapAlgorithm::OptimalFit) -/// and [`wrap_optimal_fit`]. -/// -/// This wrapping algorithm in [`wrap_optimal_fit`] considers the -/// entire paragraph to find optimal line breaks. When wrapping text, -/// "penalties" are assigned to line breaks based on the gaps left at -/// the end of lines. The penalties are given by this struct, with -/// [`Penalties::default`] assigning penalties that work well for -/// monospace text. -/// -/// If you are wrapping proportional text, you are advised to assign -/// your own penalties according to your font size. See the individual -/// penalties below for details. -/// -/// **Note:** Only available when the `smawk` Cargo feature is -/// enabled. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Penalties { - /// Per-line penalty. This is added for every line, which makes it - /// expensive to output more lines than the minimum required. - pub nline_penalty: usize, - - /// Per-character cost for lines that overflow the target line width. - /// - /// With a default value of 50², every single character costs as - /// much as leaving a gap of 50 characters behind. This is because - /// we assign as cost of `gap * gap` to a short line. When - /// wrapping monospace text, we can overflow the line by 1 - /// character in extreme cases: - /// - /// ``` - /// use textwrap::core::Word; - /// use textwrap::wrap_algorithms::{wrap_optimal_fit, Penalties}; - /// - /// let short = "foo "; - /// let long = "x".repeat(50); - /// let length = (short.len() + long.len()) as f64; - /// let fragments = vec![Word::from(short), Word::from(&long)]; - /// let penalties = Penalties::new(); - /// - /// // Perfect fit, both words are on a single line with no overflow. - /// let wrapped = wrap_optimal_fit(&fragments, &[length], &penalties).unwrap(); - /// assert_eq!(wrapped, vec![&[Word::from(short), Word::from(&long)]]); - /// - /// // The words no longer fit, yet we get a single line back. While - /// // the cost of overflow (`1 * 2500`) is the same as the cost of the - /// // gap (`50 * 50 = 2500`), the tie is broken by `nline_penalty` - /// // which makes it cheaper to overflow than to use two lines. - /// let wrapped = wrap_optimal_fit(&fragments, &[length - 1.0], &penalties).unwrap(); - /// assert_eq!(wrapped, vec![&[Word::from(short), Word::from(&long)]]); - /// - /// // The cost of overflow would be 2 * 2500, whereas the cost of - /// // the gap is only `49 * 49 + nline_penalty = 2401 + 1000 = - /// // 3401`. We therefore get two lines. - /// let wrapped = wrap_optimal_fit(&fragments, &[length - 2.0], &penalties).unwrap(); - /// assert_eq!(wrapped, vec![&[Word::from(short)], - /// &[Word::from(&long)]]); - /// ``` - /// - /// This only happens if the overflowing word is 50 characters - /// long _and_ if the word overflows the line by exactly one - /// character. If it overflows by more than one character, the - /// overflow penalty will quickly outgrow the cost of the gap, as - /// seen above. - pub overflow_penalty: usize, - - /// When should the a single word on the last line be considered - /// "too short"? - /// - /// If the last line of the text consist of a single word and if - /// this word is shorter than `1 / short_last_line_fraction` of - /// the line width, then the final line will be considered "short" - /// and `short_last_line_penalty` is added as an extra penalty. - /// - /// The effect of this is to avoid a final line consisting of a - /// single small word. For example, with a - /// `short_last_line_penalty` of 25 (the default), a gap of up to - /// 5 columns will be seen as more desirable than having a final - /// short line. - /// - /// ## Examples - /// - /// ``` - /// use textwrap::{wrap, wrap_algorithms, Options, WrapAlgorithm}; - /// - /// let text = "This is a demo of the short last line penalty."; - /// - /// // The first-fit algorithm leaves a single short word on the last line: - /// assert_eq!(wrap(text, Options::new(37).wrap_algorithm(WrapAlgorithm::FirstFit)), - /// vec!["This is a demo of the short last line", - /// "penalty."]); - /// - /// #[cfg(feature = "smawk")] { - /// let mut penalties = wrap_algorithms::Penalties::new(); - /// - /// // Since "penalty." is shorter than 25% of the line width, the - /// // optimal-fit algorithm adds a penalty of 25. This is enough - /// // to move "line " down: - /// assert_eq!(wrap(text, Options::new(37).wrap_algorithm(WrapAlgorithm::OptimalFit(penalties))), - /// vec!["This is a demo of the short last", - /// "line penalty."]); - /// - /// // We can change the meaning of "short" lines. Here, only words - /// // shorter than 1/10th of the line width will be considered short: - /// penalties.short_last_line_fraction = 10; - /// assert_eq!(wrap(text, Options::new(37).wrap_algorithm(WrapAlgorithm::OptimalFit(penalties))), - /// vec!["This is a demo of the short last line", - /// "penalty."]); - /// - /// // If desired, the penalty can also be disabled: - /// penalties.short_last_line_fraction = 4; - /// penalties.short_last_line_penalty = 0; - /// assert_eq!(wrap(text, Options::new(37).wrap_algorithm(WrapAlgorithm::OptimalFit(penalties))), - /// vec!["This is a demo of the short last line", - /// "penalty."]); - /// } - /// ``` - pub short_last_line_fraction: usize, - - /// Penalty for a last line with a single short word. - /// - /// Set this to zero if you do not want to penalize short last lines. - pub short_last_line_penalty: usize, - - /// Penalty for lines ending with a hyphen. - pub hyphen_penalty: usize, -} - -impl Penalties { - /// Default penalties for monospace text. - /// - /// The penalties here work well for monospace text. This is - /// because they expect the gaps at the end of lines to be roughly - /// in the range `0..100`. If the gaps are larger, the - /// `overflow_penalty` and `hyphen_penalty` become insignificant. - pub const fn new() -> Self { - Penalties { - nline_penalty: 1000, - overflow_penalty: 50 * 50, - short_last_line_fraction: 4, - short_last_line_penalty: 25, - hyphen_penalty: 25, - } - } -} - -impl Default for Penalties { - fn default() -> Self { - Self::new() - } -} - -/// Cache for line numbers. This is necessary to avoid a O(n**2) -/// behavior when computing line numbers in [`wrap_optimal_fit`]. -struct LineNumbers { - line_numbers: RefCell>, -} - -impl LineNumbers { - fn new(size: usize) -> Self { - let mut line_numbers = Vec::with_capacity(size); - line_numbers.push(0); - LineNumbers { - line_numbers: RefCell::new(line_numbers), - } - } - - fn get(&self, i: usize, minima: &[(usize, T)]) -> usize { - while self.line_numbers.borrow_mut().len() < i + 1 { - let pos = self.line_numbers.borrow().len(); - let line_number = 1 + self.get(minima[pos].0, minima); - self.line_numbers.borrow_mut().push(line_number); - } - - self.line_numbers.borrow()[i] - } -} - -/// Overflow error during the [`wrap_optimal_fit`] computation. -#[derive(Debug, PartialEq, Eq)] -pub struct OverflowError; - -impl std::fmt::Display for OverflowError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "wrap_optimal_fit cost computation overflowed") - } -} - -impl std::error::Error for OverflowError {} - -/// Wrap abstract fragments into lines with an optimal-fit algorithm. -/// -/// The `line_widths` slice gives the target line width for each line -/// (the last slice element is repeated as necessary). This can be -/// used to implement hanging indentation. -/// -/// The fragments must already have been split into the desired -/// widths, this function will not (and cannot) attempt to split them -/// further when arranging them into lines. -/// -/// # Optimal-Fit Algorithm -/// -/// The algorithm considers all possible break points and picks the -/// breaks which minimizes the gaps at the end of each line. More -/// precisely, the algorithm assigns a cost or penalty to each break -/// point, determined by `cost = gap * gap` where `gap = target_width - -/// line_width`. Shorter lines are thus penalized more heavily since -/// they leave behind a larger gap. -/// -/// We can illustrate this with the text “To be, or not to be: that is -/// the question”. We will be wrapping it in a narrow column with room -/// for only 10 characters. The [greedy -/// algorithm](super::wrap_first_fit) will produce these lines, each -/// annotated with the corresponding penalty: -/// -/// ```text -/// "To be, or" 1² = 1 -/// "not to be:" 0² = 0 -/// "that is" 3² = 9 -/// "the" 7² = 49 -/// "question" 2² = 4 -/// ``` -/// -/// We see that line four with “the” leaves a gap of 7 columns, which -/// gives it a penalty of 49. The sum of the penalties is 63. -/// -/// There are 10 words, which means that there are `2_u32.pow(9)` or -/// 512 different ways to typeset it. We can compute -/// the sum of the penalties for each possible line break and search -/// for the one with the lowest sum: -/// -/// ```text -/// "To be," 4² = 16 -/// "or not to" 1² = 1 -/// "be: that" 2² = 4 -/// "is the" 4² = 16 -/// "question" 2² = 4 -/// ``` -/// -/// The sum of the penalties is 41, which is better than what the -/// greedy algorithm produced. -/// -/// Searching through all possible combinations would normally be -/// prohibitively slow. However, it turns out that the problem can be -/// formulated as the task of finding column minima in a cost matrix. -/// This matrix has a special form (totally monotone) which lets us -/// use a [linear-time algorithm called -/// SMAWK](https://lib.rs/crates/smawk) to find the optimal break -/// points. -/// -/// This means that the time complexity remains O(_n_) where _n_ is -/// the number of words. Compared to -/// [`wrap_first_fit()`](super::wrap_first_fit), this function is -/// about 4 times slower. -/// -/// The optimization of per-line costs over the entire paragraph is -/// inspired by the line breaking algorithm used in TeX, as described -/// in the 1981 article [_Breaking Paragraphs into -/// Lines_](http://www.eprg.org/G53DOC/pdfs/knuth-plass-breaking.pdf) -/// by Knuth and Plass. The implementation here is based on [Python -/// code by David -/// Eppstein](https://github.com/jfinkels/PADS/blob/master/pads/wrap.py). -/// -/// # Errors -/// -/// In case of an overflow during the cost computation, an `Err` is -/// returned. Overflows happens when fragments or lines have infinite -/// widths (`f64::INFINITY`) or if the widths are so large that the -/// gaps at the end of lines have sizes larger than `f64::MAX.sqrt()` -/// (approximately 1e154): -/// -/// ``` -/// use textwrap::core::Fragment; -/// use textwrap::wrap_algorithms::{wrap_optimal_fit, OverflowError, Penalties}; -/// -/// #[derive(Debug, PartialEq)] -/// struct Word(f64); -/// -/// impl Fragment for Word { -/// fn width(&self) -> f64 { self.0 } -/// fn whitespace_width(&self) -> f64 { 1.0 } -/// fn penalty_width(&self) -> f64 { 0.0 } -/// } -/// -/// // Wrapping overflows because 1e155 * 1e155 = 1e310, which is -/// // larger than f64::MAX: -/// assert_eq!(wrap_optimal_fit(&[Word(0.0), Word(0.0)], &[1e155], &Penalties::default()), -/// Err(OverflowError)); -/// ``` -/// -/// When using fragment widths and line widths which fit inside an -/// `u64`, overflows cannot happen. This means that fragments derived -/// from a `&str` cannot cause overflows. -/// -/// **Note:** Only available when the `smawk` Cargo feature is -/// enabled. -pub fn wrap_optimal_fit<'a, 'b, T: Fragment>( - fragments: &'a [T], - line_widths: &'b [f64], - penalties: &'b Penalties, -) -> Result, OverflowError> { - // The final line width is used for all remaining lines. - let default_line_width = line_widths.last().copied().unwrap_or(0.0); - let mut widths = Vec::with_capacity(fragments.len() + 1); - let mut width = 0.0; - widths.push(width); - for fragment in fragments { - width += fragment.width() + fragment.whitespace_width(); - widths.push(width); - } - - let line_numbers = LineNumbers::new(fragments.len()); - - let minima = smawk::online_column_minima(0.0, widths.len(), |minima, i, j| { - // Line number for fragment `i`. - let line_number = line_numbers.get(i, minima); - let line_width = line_widths - .get(line_number) - .copied() - .unwrap_or(default_line_width); - let target_width = line_width.max(1.0); - - // Compute the width of a line spanning fragments[i..j] in - // constant time. We need to adjust widths[j] by subtracting - // the whitespace of fragment[j-1] and then add the penalty. - let line_width = widths[j] - widths[i] - fragments[j - 1].whitespace_width() - + fragments[j - 1].penalty_width(); - - // We compute cost of the line containing fragments[i..j]. We - // start with values[i].1, which is the optimal cost for - // breaking before fragments[i]. - // - // First, every extra line cost NLINE_PENALTY. - let mut cost = minima[i].1 + penalties.nline_penalty as f64; - - // Next, we add a penalty depending on the line length. - if line_width > target_width { - // Lines that overflow get a hefty penalty. - let overflow = line_width - target_width; - cost += overflow * penalties.overflow_penalty as f64; - } else if j < fragments.len() { - // Other lines (except for the last line) get a milder - // penalty which depend on the size of the gap. - let gap = target_width - line_width; - cost += gap * gap; - } else if i + 1 == j - && line_width < target_width / penalties.short_last_line_fraction as f64 - { - // The last line can have any size gap, but we do add a - // penalty if the line is very short (typically because it - // contains just a single word). - cost += penalties.short_last_line_penalty as f64; - } - - // Finally, we discourage hyphens. - if fragments[j - 1].penalty_width() > 0.0 { - // TODO: this should use a penalty value from the fragment - // instead. - cost += penalties.hyphen_penalty as f64; - } - - cost - }); - - for (_, cost) in &minima { - if cost.is_infinite() { - return Err(OverflowError); - } - } - - let mut lines = Vec::with_capacity(line_numbers.get(fragments.len(), &minima)); - let mut pos = fragments.len(); - loop { - let prev = minima[pos].0; - lines.push(&fragments[prev..pos]); - pos = prev; - if pos == 0 { - break; - } - } - - lines.reverse(); - Ok(lines) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[derive(Debug, PartialEq)] - struct Word(f64); - - #[rustfmt::skip] - impl Fragment for Word { - fn width(&self) -> f64 { self.0 } - fn whitespace_width(&self) -> f64 { 1.0 } - fn penalty_width(&self) -> f64 { 0.0 } - } - - #[test] - fn wrap_fragments_with_infinite_widths() { - let words = vec![Word(f64::INFINITY)]; - assert_eq!( - wrap_optimal_fit(&words, &[0.0], &Penalties::default()), - Err(OverflowError) - ); - } - - #[test] - fn wrap_fragments_with_huge_widths() { - let words = vec![Word(1e200), Word(1e250), Word(1e300)]; - assert_eq!( - wrap_optimal_fit(&words, &[1e300], &Penalties::default()), - Err(OverflowError) - ); - } - - #[test] - fn wrap_fragments_with_large_widths() { - // The gaps will be of the sizes between 1e25 and 1e75. This - // makes the `gap * gap` cost fit comfortably in a f64. - let words = vec![Word(1e25), Word(1e50), Word(1e75)]; - assert_eq!( - wrap_optimal_fit(&words, &[1e100], &Penalties::default()), - Ok(vec![&vec![Word(1e25), Word(1e50), Word(1e75)][..]]) - ); - } -} diff --git a/third_party/rust/textwrap/tests/indent.rs b/third_party/rust/textwrap/tests/indent.rs deleted file mode 100644 index 9dd5ad2642d4..000000000000 --- a/third_party/rust/textwrap/tests/indent.rs +++ /dev/null @@ -1,88 +0,0 @@ -/// tests cases ported over from python standard library -use textwrap::{dedent, indent}; - -const ROUNDTRIP_CASES: [&str; 3] = [ - // basic test case - "Hi.\nThis is a test.\nTesting.", - // include a blank line - "Hi.\nThis is a test.\n\nTesting.", - // include leading and trailing blank lines - "\nHi.\nThis is a test.\nTesting.\n", -]; - -const WINDOWS_CASES: [&str; 2] = [ - // use windows line endings - "Hi.\r\nThis is a test.\r\nTesting.", - // pathological case - "Hi.\r\nThis is a test.\n\r\nTesting.\r\n\n", -]; - -#[test] -fn test_indent_nomargin_default() { - // indent should do nothing if 'prefix' is empty. - for text in ROUNDTRIP_CASES.iter() { - assert_eq!(&indent(text, ""), text); - } - for text in WINDOWS_CASES.iter() { - assert_eq!(&indent(text, ""), text); - } -} - -#[test] -fn test_roundtrip_spaces() { - // A whitespace prefix should roundtrip with dedent - for text in ROUNDTRIP_CASES.iter() { - assert_eq!(&dedent(&indent(text, " ")), text); - } -} - -#[test] -fn test_roundtrip_tabs() { - // A whitespace prefix should roundtrip with dedent - for text in ROUNDTRIP_CASES.iter() { - assert_eq!(&dedent(&indent(text, "\t\t")), text); - } -} - -#[test] -fn test_roundtrip_mixed() { - // A whitespace prefix should roundtrip with dedent - for text in ROUNDTRIP_CASES.iter() { - assert_eq!(&dedent(&indent(text, " \t \t ")), text); - } -} - -#[test] -fn test_indent_default() { - // Test default indenting of lines that are not whitespace only - let prefix = " "; - let expected = [ - // Basic test case - " Hi.\n This is a test.\n Testing.", - // Include a blank line - " Hi.\n This is a test.\n\n Testing.", - // Include leading and trailing blank lines - "\n Hi.\n This is a test.\n Testing.\n", - ]; - for (text, expect) in ROUNDTRIP_CASES.iter().zip(expected.iter()) { - assert_eq!(&indent(text, prefix), expect) - } - let expected = [ - // Use Windows line endings - " Hi.\r\n This is a test.\r\n Testing.", - // Pathological case - " Hi.\r\n This is a test.\n\r\n Testing.\r\n\n", - ]; - for (text, expect) in WINDOWS_CASES.iter().zip(expected.iter()) { - assert_eq!(&indent(text, prefix), expect) - } -} - -#[test] -fn indented_text_should_have_the_same_number_of_lines_as_the_original_text() { - let texts = ["foo\nbar", "foo\nbar\n", "foo\nbar\nbaz"]; - for original in texts.iter() { - let indented = indent(original, ""); - assert_eq!(&indented, original); - } -} diff --git a/third_party/rust/textwrap/tests/version-numbers.rs b/third_party/rust/textwrap/tests/version-numbers.rs deleted file mode 100644 index 3f429b187adb..000000000000 --- a/third_party/rust/textwrap/tests/version-numbers.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[test] -fn test_readme_deps() { - version_sync::assert_markdown_deps_updated!("README.md"); -} - -#[test] -fn test_changelog() { - version_sync::assert_contains_regex!( - "CHANGELOG.md", - r"^## Version {version} \(20\d\d-\d\d-\d\d\)" - ); -} - -#[test] -fn test_html_root_url() { - version_sync::assert_html_root_url_updated!("src/lib.rs"); -} - -#[test] -fn test_dependency_graph() { - version_sync::assert_contains_regex!("src/lib.rs", "master/images/textwrap-{version}.svg"); -} diff --git a/third_party/rust/unicode-linebreak/.cargo-checksum.json b/third_party/rust/unicode-linebreak/.cargo-checksum.json deleted file mode 100644 index 2b4a10002a35..000000000000 --- a/third_party/rust/unicode-linebreak/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"7f8e0b5d66e9c5621c5fb57d4b16b801a24061e37ee337e06f8a004e6895a8dc","LICENSE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","src/lib.rs":"ef4f143f99e9ef4f17dab02e1b80ed3ac484ae58e0bb64164920720e0ca9425f","src/shared.rs":"e0c98ea10f78491f567e2a18bcb41b3f0ae01ce587d8b3a16ce0dc1097919109","src/tables.rs":"1821b437dfb31164ce8180af3937ca42270f1edf963a2d2e41cbaaf999553c94"},"package":"3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"} \ No newline at end of file diff --git a/third_party/rust/unicode-linebreak/Cargo.toml b/third_party/rust/unicode-linebreak/Cargo.toml deleted file mode 100644 index 857c779d676a..000000000000 --- a/third_party/rust/unicode-linebreak/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.56" -name = "unicode-linebreak" -version = "0.1.5" -authors = ["Axel Forsman "] -include = [ - "src/**/*", - "LICENSE", -] -description = "Implementation of the Unicode Line Breaking Algorithm" -homepage = "https://github.com/axelf4/unicode-linebreak" -readme = "README.md" -keywords = [ - "unicode", - "text", - "layout", -] -categories = ["internationalization"] -license = "Apache-2.0" -repository = "https://github.com/axelf4/unicode-linebreak" diff --git a/third_party/rust/unicode-linebreak/LICENSE b/third_party/rust/unicode-linebreak/LICENSE deleted file mode 100644 index 261eeb9e9f8b..000000000000 --- a/third_party/rust/unicode-linebreak/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/third_party/rust/unicode-linebreak/src/lib.rs b/third_party/rust/unicode-linebreak/src/lib.rs deleted file mode 100644 index ca473d8494d5..000000000000 --- a/third_party/rust/unicode-linebreak/src/lib.rs +++ /dev/null @@ -1,160 +0,0 @@ -//! Implementation of the Line Breaking Algorithm described in [Unicode Standard Annex #14][UAX14]. -//! -//! Given an input text, locates "line break opportunities", or positions appropriate for wrapping -//! lines when displaying text. -//! -//! # Example -//! -//! ``` -//! use unicode_linebreak::{linebreaks, BreakOpportunity::{Mandatory, Allowed}}; -//! -//! let text = "a b \nc"; -//! assert!(linebreaks(text).eq([ -//! (2, Allowed), // May break after first space -//! (5, Mandatory), // Must break after line feed -//! (6, Mandatory) // Must break at end of text, so that there always is at least one LB -//! ])); -//! ``` -//! -//! [UAX14]: https://www.unicode.org/reports/tr14/ - -#![no_std] -#![deny(missing_docs, missing_debug_implementations)] - -use core::iter::once; - -/// The [Unicode version](https://www.unicode.org/versions/) conformed to. -pub const UNICODE_VERSION: (u8, u8, u8) = (15, 0, 0); - -include!("shared.rs"); -include!("tables.rs"); - -/// Returns the line break property of the specified code point. -/// -/// # Examples -/// -/// ``` -/// use unicode_linebreak::{BreakClass, break_property}; -/// assert_eq!(break_property(0x2CF3), BreakClass::Alphabetic); -/// ``` -#[inline(always)] -pub fn break_property(codepoint: u32) -> BreakClass { - const BMP_INDEX_LENGTH: u32 = BMP_LIMIT >> BMP_SHIFT; - const OMITTED_BMP_INDEX_1_LENGTH: u32 = BMP_LIMIT >> SHIFT_1; - - let data_pos = if codepoint < BMP_LIMIT { - let i = codepoint >> BMP_SHIFT; - BREAK_PROP_TRIE_INDEX[i as usize] + (codepoint & (BMP_DATA_BLOCK_LENGTH - 1)) as u16 - } else if codepoint < BREAK_PROP_TRIE_HIGH_START { - let i1 = codepoint >> SHIFT_1; - let i2 = BREAK_PROP_TRIE_INDEX - [(i1 + BMP_INDEX_LENGTH - OMITTED_BMP_INDEX_1_LENGTH) as usize] - + ((codepoint >> SHIFT_2) & (INDEX_2_BLOCK_LENGTH - 1)) as u16; - let i3_block = BREAK_PROP_TRIE_INDEX[i2 as usize]; - let i3_pos = ((codepoint >> SHIFT_3) & (INDEX_3_BLOCK_LENGTH - 1)) as u16; - - debug_assert!(i3_block & 0x8000 == 0, "18-bit indices are unexpected"); - let data_block = BREAK_PROP_TRIE_INDEX[(i3_block + i3_pos) as usize]; - data_block + (codepoint & (SMALL_DATA_BLOCK_LENGTH - 1)) as u16 - } else { - return XX; - }; - BREAK_PROP_TRIE_DATA[data_pos as usize] -} - -/// Break opportunity type. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum BreakOpportunity { - /// A line must break at this spot. - Mandatory, - /// A line is allowed to end at this spot. - Allowed, -} - -/// Returns an iterator over line break opportunities in the specified string. -/// -/// Break opportunities are given as tuples of the byte index of the character succeeding the break -/// and the type. -/// -/// Uses the default Line Breaking Algorithm with the tailoring that Complex-Context Dependent -/// (SA) characters get resolved to Ordinary Alphabetic and Symbol Characters (AL) regardless of -/// General_Category. -/// -/// # Examples -/// -/// ``` -/// use unicode_linebreak::{linebreaks, BreakOpportunity::{Mandatory, Allowed}}; -/// assert!(linebreaks("Hello world!").eq(vec![(6, Allowed), (12, Mandatory)])); -/// ``` -pub fn linebreaks(s: &str) -> impl Iterator + Clone + '_ { - use BreakOpportunity::{Allowed, Mandatory}; - - s.char_indices() - .map(|(i, c)| (i, break_property(c as u32) as u8)) - .chain(once((s.len(), eot))) - .scan((sot, false), |state, (i, cls)| { - // ZWJ is handled outside the table to reduce its size - let val = PAIR_TABLE[state.0 as usize][cls as usize]; - let is_mandatory = val & MANDATORY_BREAK_BIT != 0; - let is_break = val & ALLOWED_BREAK_BIT != 0 && (!state.1 || is_mandatory); - *state = ( - val & !(ALLOWED_BREAK_BIT | MANDATORY_BREAK_BIT), - cls == BreakClass::ZeroWidthJoiner as u8, - ); - - Some((i, is_break, is_mandatory)) - }) - .filter_map(|(i, is_break, is_mandatory)| { - if is_break { - Some((i, if is_mandatory { Mandatory } else { Allowed })) - } else { - None - } - }) -} - -/// Divides the string at the last index where further breaks do not depend on prior context. -/// -/// The trivial index at `eot` is excluded. -/// -/// A common optimization is to determine only the nearest line break opportunity before the first -/// character that would cause the line to become overfull, requiring backward traversal, of which -/// there are two approaches: -/// -/// * Cache breaks from forward traversals -/// * Step backward and with `split_at_safe` find a pos to safely search forward from, repeatedly -/// -/// # Examples -/// -/// ``` -/// use unicode_linebreak::{linebreaks, split_at_safe}; -/// let s = "Not allowed to break within em dashes: — —"; -/// let (prev, safe) = split_at_safe(s); -/// let n = prev.len(); -/// assert!(linebreaks(safe).eq(linebreaks(s).filter_map(|(i, x)| i.checked_sub(n).map(|i| (i, x))))); -/// ``` -pub fn split_at_safe(s: &str) -> (&str, &str) { - let mut chars = s.char_indices().rev().scan(None, |state, (i, c)| { - let cls = break_property(c as u32); - let is_safe_pair = state - .replace(cls) - .map_or(false, |prev| is_safe_pair(cls, prev)); // Reversed since iterating backwards - Some((i, is_safe_pair)) - }); - chars.find(|&(_, is_safe_pair)| is_safe_pair); - // Include preceding char for `linebreaks` to pick up break before match (disallowed after sot) - s.split_at(chars.next().map_or(0, |(i, _)| i)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - assert_eq!(break_property(0xA), BreakClass::LineFeed); - assert_eq!(break_property(0xDB80), BreakClass::Surrogate); - assert_eq!(break_property(0xe01ef), BreakClass::CombiningMark); - assert_eq!(break_property(0x10ffff), BreakClass::Unknown); - } -} diff --git a/third_party/rust/unicode-linebreak/src/shared.rs b/third_party/rust/unicode-linebreak/src/shared.rs deleted file mode 100644 index c73819f069df..000000000000 --- a/third_party/rust/unicode-linebreak/src/shared.rs +++ /dev/null @@ -1,134 +0,0 @@ -/// Unicode line breaking class. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -#[repr(u8)] -pub enum BreakClass { - // Non-tailorable - /// Cause a line break (after) - Mandatory, - /// Cause a line break (after), except between CR and LF - CarriageReturn, - /// Cause a line break (after) - LineFeed, - /// Prohibit a line break between the character and the preceding character - CombiningMark, - /// Cause a line break (after) - NextLine, - /// Do not occur in well-formed text - Surrogate, - /// Prohibit line breaks before and after - WordJoiner, - /// Provide a break opportunity - ZeroWidthSpace, - /// Prohibit line breaks before and after - NonBreakingGlue, - /// Enable indirect line breaks - Space, - /// Prohibit line breaks within joiner sequences - ZeroWidthJoiner, - // Break opportunities - /// Provide a line break opportunity before and after the character - BeforeAndAfter, - /// Generally provide a line break opportunity after the character - After, - /// Generally provide a line break opportunity before the character - Before, - /// Provide a line break opportunity after the character, except in numeric context - Hyphen, - /// Provide a line break opportunity contingent on additional information - Contingent, - // Characters prohibiting certain breaks - /// Prohibit line breaks before - ClosePunctuation, - /// Prohibit line breaks before - CloseParenthesis, - /// Prohibit line breaks before - Exclamation, - /// Allow only indirect line breaks between pairs - Inseparable, - /// Allow only indirect line breaks before - NonStarter, - /// Prohibit line breaks after - OpenPunctuation, - /// Act like they are both opening and closing - Quotation, - // Numeric context - /// Prevent breaks after any and before numeric - InfixSeparator, - /// Form numeric expressions for line breaking purposes - Numeric, - /// Do not break following a numeric expression - Postfix, - /// Do not break in front of a numeric expression - Prefix, - /// Prevent a break before, and allow a break after - Symbol, - // Other characters - /// Act like AL when the resolved EAW is N; otherwise, act as ID - Ambiguous, - /// Are alphabetic characters or symbols that are used with alphabetic characters - Alphabetic, - /// Treat as NS or ID for strict or normal breaking. - ConditionalJapaneseStarter, - /// Do not break from following Emoji Modifier - EmojiBase, - /// Do not break from preceding Emoji Base - EmojiModifier, - /// Form Korean syllable blocks - HangulLvSyllable, - /// Form Korean syllable blocks - HangulLvtSyllable, - /// Do not break around a following hyphen; otherwise act as Alphabetic - HebrewLetter, - /// Break before or after, except in some numeric context - Ideographic, - /// Form Korean syllable blocks - HangulLJamo, - /// Form Korean syllable blocks - HangulVJamo, - /// Form Korean syllable blocks - HangulTJamo, - /// Keep pairs together. For pairs, break before and after other classes - RegionalIndicator, - /// Provide a line break opportunity contingent on additional, language-specific context analysis - ComplexContext, - /// Have as yet unknown line breaking behavior or unassigned code positions - Unknown, -} - -use BreakClass::{ - After as BA, Alphabetic as AL, Ambiguous as AI, Before as BB, BeforeAndAfter as B2, - CarriageReturn as CR, CloseParenthesis as CP, ClosePunctuation as CL, CombiningMark as CM, - ComplexContext as SA, ConditionalJapaneseStarter as CJ, Contingent as CB, EmojiBase as EB, - EmojiModifier as EM, Exclamation as EX, HangulLJamo as JL, HangulLvSyllable as H2, - HangulLvtSyllable as H3, HangulTJamo as JT, HangulVJamo as JV, HebrewLetter as HL, - Hyphen as HY, Ideographic as ID, InfixSeparator as IS, Inseparable as IN, LineFeed as LF, - Mandatory as BK, NextLine as NL, NonBreakingGlue as GL, NonStarter as NS, Numeric as NU, - OpenPunctuation as OP, Postfix as PO, Prefix as PR, Quotation as QU, RegionalIndicator as RI, - Space as SP, Surrogate as SG, Symbol as SY, Unknown as XX, WordJoiner as WJ, - ZeroWidthJoiner as ZWJ, ZeroWidthSpace as ZW, -}; - -/// Ceiling for code points in the Basic Multilingual Place (BMP). -const BMP_LIMIT: u32 = 0x10000; - -/// Shift size for getting index-3 table offset. -const SHIFT_3: u32 = 4; -/// Shift size for getting index-2 table offset. -const SHIFT_2: u32 = 5 + SHIFT_3; -/// Shift size for getting index-1 table offset. -const SHIFT_1: u32 = 5 + SHIFT_2; -/// Shift size for getting BMP block start. -const BMP_SHIFT: u32 = 6; - -const INDEX_2_BLOCK_LENGTH: u32 = 1 << (SHIFT_1 - SHIFT_2); -const INDEX_3_BLOCK_LENGTH: u32 = 1 << (SHIFT_2 - SHIFT_3); -const SMALL_DATA_BLOCK_LENGTH: u32 = 1 << SHIFT_3; -const BMP_DATA_BLOCK_LENGTH: u32 = 1 << BMP_SHIFT; - -const ALLOWED_BREAK_BIT: u8 = 0x80; -const MANDATORY_BREAK_BIT: u8 = 0x40; - -#[allow(non_upper_case_globals)] -const eot: u8 = 43; -#[allow(non_upper_case_globals)] -const sot: u8 = 44; diff --git a/third_party/rust/unicode-linebreak/src/tables.rs b/third_party/rust/unicode-linebreak/src/tables.rs deleted file mode 100644 index 1a5d16b5ce8f..000000000000 --- a/third_party/rust/unicode-linebreak/src/tables.rs +++ /dev/null @@ -1,10 +0,0 @@ -const BREAK_PROP_TRIE_HIGH_START: u32 = 918016; -static BREAK_PROP_TRIE_INDEX: [u16; 2844] = [0, 64, 127, 191, 247, 247, 247, 247, 247, 247, 247, 304, 368, 417, 481, 247, 247, 247, 542, 247, 558, 607, 662, 726, 790, 843, 247, 892, 950, 1003, 1029, 1093, 1157, 1221, 1270, 1324, 1384, 1446, 1509, 1571, 1634, 1696, 1759, 1821, 1885, 1947, 2009, 2071, 2135, 2197, 2260, 2322, 2386, 2448, 2512, 2576, 2639, 2703, 2766, 2830, 2894, 2958, 3016, 3080, 3144, 3208, 3256, 3314, 3378, 3410, 3442, 3482, 247, 3546, 3601, 3663, 3710, 3747, 3782, 3814, 3878, 247, 247, 247, 247, 247, 247, 247, 247, 247, 3942, 3974, 4038, 4102, 3144, 4166, 4230, 4262, 4326, 4374, 4438, 4502, 4566, 4620, 4661, 4694, 4758, 4807, 4871, 4930, 4994, 5052, 5112, 5176, 5240, 5301, 247, 247, 247, 5365, 247, 247, 247, 247, 5429, 5487, 553, 5551, 5615, 5677, 5741, 5803, 5867, 5911, 5969, 6015, 6079, 6141, 6203, 6267, 6323, 247, 247, 6366, 6418, 6482, 6514, 6515, 6514, 6566, 6630, 6690, 6754, 6818, 6882, 6943, 7004, 7045, 7099, 7158, 247, 247, 247, 247, 247, 247, 7219, 7259, 247, 247, 247, 247, 247, 7321, 7375, 247, 247, 247, 247, 7398, 7462, 7510, 7574, 7606, 7670, 7734, 7798, 7825, 7889, 7889, 7889, 7931, 7995, 8059, 8120, 8181, 8245, 7889, 7809, 8294, 8262, 8358, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 247, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 8401, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 8452, 8509, 247, 247, 247, 247, 8573, 8637, 8699, 8731, 247, 247, 247, 8795, 8857, 8921, 8985, 9043, 9107, 9164, 9228, 9291, 9355, 9419, 3144, 9480, 9543, 9591, 247, 9639, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9723, 9703, 9711, 9719, 9727, 9707, 9715, 9779, 9836, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9900, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 10028, 10092, 247, 10153, 247, 247, 247, 247, 10172, 247, 10236, 10292, 10356, 10416, 247, 10470, 10534, 10596, 10645, 10708, 2656, 2686, 2715, 2746, 2778, 2778, 2778, 2779, 2778, 2778, 2778, 2779, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2811, 2843, 503, 247, 508, 10772, 616, 616, 9964, 9964, 247, 247, 247, 247, 247, 247, 247, 1253, 10788, 247, 247, 2531, 247, 247, 247, 247, 500, 2522, 1837, 9964, 9964, 247, 247, 10795, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 2522, 247, 247, 247, 1837, 551, 2055, 247, 247, 7593, 247, 1253, 247, 247, 10811, 247, 10827, 247, 247, 9631, 10842, 9964, 9964, 247, 247, 247, 247, 247, 247, 247, 247, 247, 616, 2235, 247, 247, 9631, 247, 2055, 247, 247, 1995, 247, 247, 247, 10844, 504, 504, 10859, 513, 10873, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 4421, 247, 4422, 1995, 9964, 509, 247, 247, 10889, 9964, 9964, 9964, 9964, 10905, 247, 247, 10915, 247, 10930, 247, 247, 247, 500, 783, 9964, 9964, 9964, 247, 10943, 247, 10954, 247, 1254, 9964, 9964, 9964, 9964, 247, 247, 247, 9627, 247, 630, 247, 247, 10970, 1769, 247, 10986, 4022, 11002, 247, 247, 247, 247, 9964, 9964, 247, 247, 11018, 11034, 247, 247, 247, 11050, 247, 624, 247, 1261, 247, 11066, 781, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 4022, 9964, 9964, 9964, 247, 247, 247, 6454, 247, 247, 247, 4028, 247, 247, 4052, 2235, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 500, 247, 247, 11082, 6455, 9964, 9964, 9964, 4858, 247, 247, 1995, 247, 362, 11098, 9964, 247, 11114, 9964, 9964, 247, 2055, 9964, 247, 4421, 549, 247, 247, 360, 11130, 630, 2920, 11146, 549, 247, 247, 11161, 11175, 247, 4022, 2235, 549, 247, 361, 11191, 11207, 247, 247, 11223, 549, 247, 247, 365, 11239, 11255, 494, 6452, 247, 513, 356, 11271, 11286, 9964, 9964, 9964, 11302, 501, 11317, 247, 247, 353, 4811, 2235, 11333, 629, 506, 11348, 1947, 11364, 11378, 4817, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 363, 11394, 11410, 6455, 9964, 247, 247, 247, 368, 11426, 2235, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 353, 11442, 11457, 11466, 9964, 9964, 247, 247, 247, 368, 11482, 2235, 11498, 9964, 247, 247, 357, 11514, 2235, 9964, 9964, 9964, 3144, 2817, 2686, 11530, 9476, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 356, 1067, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 940, 10032, 11546, 11558, 247, 11574, 11588, 2235, 9964, 9964, 9964, 9964, 622, 247, 247, 11604, 11619, 9964, 8688, 247, 247, 11635, 11651, 11667, 247, 247, 358, 11683, 11698, 247, 247, 247, 247, 4022, 11714, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 506, 247, 353, 3033, 11730, 940, 2522, 11746, 247, 3005, 3032, 4815, 9964, 9964, 9964, 9964, 1801, 247, 247, 11761, 11776, 2235, 11792, 247, 4674, 11808, 2235, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 11824, 11840, 493, 247, 11852, 11866, 2235, 9964, 9964, 9964, 9964, 9964, 1837, 247, 11882, 11897, 11911, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 3798, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 247, 247, 500, 11926, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 6453, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 247, 247, 6454, 247, 247, 247, 247, 247, 11942, 247, 247, 11956, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 11966, 247, 247, 247, 247, 247, 247, 247, 247, 11982, 11998, 4816, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 3955, 247, 247, 247, 247, 4421, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 4022, 247, 500, 12014, 247, 247, 247, 247, 500, 2235, 247, 616, 12030, 247, 247, 247, 12046, 12058, 12074, 513, 1256, 247, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 247, 12085, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 2056, 367, 368, 368, 12101, 549, 9964, 9964, 9964, 9964, 12117, 4820, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7869, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 4422, 9964, 9964, 7868, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 1671, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7950, 12131, 9964, 12147, 12159, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7865, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 247, 247, 1253, 2522, 4022, 12175, 4818, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 368, 368, 1000, 368, 4815, 247, 247, 247, 247, 247, 247, 247, 6453, 9964, 9964, 9964, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 4422, 247, 247, 623, 247, 247, 247, 12191, 368, 12204, 247, 12216, 247, 247, 247, 1253, 9964, 247, 247, 247, 247, 12230, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 6453, 247, 6453, 247, 247, 247, 247, 247, 4421, 247, 4022, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 247, 247, 247, 510, 247, 247, 247, 502, 12244, 12258, 511, 247, 247, 247, 3549, 1670, 247, 3600, 12271, 493, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 624, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 12281, 12295, 12295, 12295, 368, 368, 368, 11672, 368, 368, 452, 12311, 12323, 4860, 678, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 500, 12335, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 3033, 12351, 12365, 247, 247, 247, 616, 9964, 4856, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 247, 2522, 12381, 9307, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 12397, 9964, 247, 247, 356, 12413, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 247, 356, 2235, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 12429, 500, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 625, 4815, 9964, 9964, 247, 247, 247, 247, 12445, 12461, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 494, 247, 247, 10340, 12477, 9964, 9964, 9964, 9964, 494, 247, 247, 616, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 511, 247, 12492, 12505, 12519, 12535, 12549, 12557, 505, 2055, 12572, 2055, 9964, 9964, 9964, 6455, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 12588, 6514, 6564, 6514, 6514, 6514, 12604, 6514, 6514, 6514, 12588, 7889, 7889, 7889, 12617, 12623, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 12639, 12645, 7889, 12652, 12666, 7889, 7889, 12679, 7889, 7889, 7889, 7889, 12695, 12710, 12720, 12727, 12742, 12756, 12772, 12786, 7889, 7889, 7889, 7889, 6936, 11875, 12802, 6416, 6933, 7889, 7889, 12814, 7889, 12830, 7889, 7889, 7889, 12842, 7889, 12854, 7889, 7889, 7889, 7889, 12865, 247, 247, 12881, 7889, 7889, 12641, 12897, 12903, 7889, 7889, 7889, 247, 247, 247, 247, 247, 247, 247, 12919, 247, 247, 247, 247, 247, 12802, 7889, 7889, 6402, 247, 247, 247, 6935, 6933, 247, 247, 6935, 247, 6400, 7889, 7889, 7889, 7889, 7889, 12935, 12718, 12751, 12950, 7889, 7889, 7889, 12750, 7889, 7889, 7889, 12965, 12713, 12980, 7889, 7889, 247, 247, 247, 247, 247, 12919, 7889, 7889, 7889, 7889, 7889, 7889, 12898, 7889, 7889, 12702, 247, 247, 247, 247, 247, 247, 247, 247, 247, 512, 247, 247, 1253, 9964, 9964, 2235, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7889, 7863, 2093, 9964, 368, 368, 368, 368, 368, 368, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 9964, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 9964, 1077, 1109, 1141, 1173, 1205, 1237, 1269, 1295, 1327, 1359, 1391, 1423, 1455, 1487, 1519, 1546, 1578, 1585, 1617, 896, 896, 896, 896, 1638, 1578, 1670, 1699, 896, 896, 896, 896, 896, 1731, 1760, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 1578, 1792, 896, 1820, 202, 202, 202, 202, 202, 202, 202, 202, 1852, 202, 1884, 1903, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 1920, 1952, 1975, 896, 896, 896, 896, 2007, 896, 896, 896, 896, 896, 896, 896, 2023, 2055, 2087, 2119, 2141, 1578, 2173, 896, 2189, 2221, 2244, 2263, 2279, 2311, 896, 2336, 2368, 2400, 2432, 2464, 2496, 2528, 2560, 202, 2592, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 2592, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 896, 2624]; -static BREAK_PROP_TRIE_DATA: [BreakClass; 12996] = [ -CM,CM,CM,CM,CM,CM,CM,CM,CM,BA,LF,BK,BK,CR,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,SP,EX,QU,AL,PR,PO,AL,QU,OP,CP,AL,PR,IS,HY,IS,SY,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,IS,IS,AL,AL,AL,EX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,PR,CP,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,BA,CL,AL,CM,CM,CM,CM,CM,NL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,GL,OP,PO,PR,PR,PR,AL,AI,AI,AL,AI,QU,AL,BA,AL,AL,PO,PR,AI,AI,BB,AL,AI,AI,AI,AI,AI,QU,AI,AI,AI,OP,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,BB,AI,AI,AI,BB,AI,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,AI,AI,AI,AI,AL,AI,AL,BB,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,GL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,GL,GL,GL,GL,GL,GL,GL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,IS,AL,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,IS,BA,XX,XX,AL,AL,PR,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,BA,CM,AL,CM,CM,AL,CM,CM,EX,CM,XX,XX,XX,XX,XX,XX,XX,XX,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,XX,XX,XX,XX,HL,HL,HL,HL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,PO,PO,PO,IS,IS,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,EX,CM,EX,EX,EX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,PO,NU,NU,AL,AL,AL,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,EX,AL,CM,CM,CM,CM,CM,CM,CM,AL,AL,CM,CM,CM,CM,CM,CM,AL,AL,CM,CM,AL,CM,CM,CM,CM,AL,AL,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,IS,EX,AL,XX,XX,CM,PR,PR,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,CM,CM,CM,AL,CM,CM,CM,CM,CM,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,XX,XX,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,BA,BA,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,XX,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,XX,XX,XX,AL,AL,AL,AL,XX,XX,CM,AL,CM,CM,CM,CM,CM,XX,XX,CM,CM,XX,XX,CM,CM,CM,AL,XX,XX,XX,XX,XX,XX,XX,XX,CM,XX,XX,XX,XX,AL,AL,XX,AL,AL,AL,CM,CM,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,PO,PO,AL,AL,AL,AL,AL,PO,AL,PR,AL,AL,CM,XX,CM,CM,CM,XX,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,XX,AL,AL,XX,AL,AL,XX,XX,CM,XX,CM,CM,CM,XX,XX,XX,XX,CM,CM,XX,XX,CM,CM,CM,XX,XX,XX,CM,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,XX,AL,XX,XX,XX,XX,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,CM,CM,AL,AL,AL,CM,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,CM,CM,CM,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,XX,AL,AL,AL,AL,AL,XX,XX,CM,AL,CM,CM,CM,CM,CM,CM,XX,CM,CM,CM,XX,CM,CM,CM,XX,XX,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,CM,CM,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,PR,XX,XX,XX,XX,XX,XX,XX,AL,CM,CM,CM,CM,CM,CM,XX,CM,CM,CM,XX,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,XX,AL,AL,AL,AL,AL,XX,XX,CM,AL,CM,CM,CM,CM,CM,XX,XX,CM,CM,XX,XX,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,CM,CM,CM,XX,XX,XX,XX,AL,AL,XX,AL,AL,AL,CM,CM,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,CM,AL,XX,AL,AL,AL,AL,AL,AL,XX,XX,XX,AL,AL,AL,XX,AL,AL,AL,AL,XX,XX,XX,AL,AL,XX,AL,XX,AL,AL,XX,XX,XX,AL,AL,XX,XX,XX,AL,AL,AL,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,CM,CM,CM,XX,XX,XX,CM,CM,CM,XX,CM,CM,CM,CM,XX,XX,AL,XX,XX,XX,XX,XX,XX,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,AL,PR,AL,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,CM,AL,CM,CM,CM,CM,CM,XX,CM,CM,CM,XX,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,CM,CM,XX,AL,AL,AL,XX,XX,AL,XX,XX,AL,AL,CM,CM,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,XX,XX,XX,BB,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,BB,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,XX,XX,CM,AL,CM,CM,CM,CM,CM,XX,CM,CM,CM,XX,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,CM,CM,XX,XX,XX,XX,XX,XX,AL,AL,XX,AL,AL,CM,CM,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,AL,AL,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,AL,CM,CM,CM,CM,CM,XX,CM,CM,CM,XX,CM,CM,CM,CM,AL,AL,XX,XX,XX,XX,AL,AL,AL,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,AL,PO,AL,AL,AL,AL,AL,AL,XX,CM,CM,CM,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,CM,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,XX,CM,XX,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,CM,CM,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,XX,XX,XX,PR,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,AL,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,BA,BA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,SA,SA,XX,SA,XX,SA,SA,SA,SA,SA,XX,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,SA,XX,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,XX,SA,SA,SA,SA,SA,XX,SA,XX,SA,SA,SA,SA,SA,SA,SA,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,SA,SA,SA,SA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,BB,BB,BB,BB,AL,BB,BB,GL,BB,BB,BA,GL,EX,EX,EX,EX,EX,GL,AL,EX,AL,AL,AL,CM,CM,AL,AL,AL,AL,AL,AL,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,BA,CM,AL,CM,AL,CM,OP,CL,OP,CL,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,BA,CM,CM,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,BA,BA,AL,AL,AL,AL,AL,AL,CM,AL,AL,AL,AL,AL,AL,XX,AL,AL,BB,BB,BA,BB,AL,AL,AL,AL,AL,GL,GL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,BA,BA,AL,AL,AL,AL,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,SA,SA,SA,SA,SA,SA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,XX,XX,XX,XX,XX,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,XX,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,CM,CM,CM,AL,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,XX,XX,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,BA,BA,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,BA,BA,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,XX,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,BA,BA,NS,SA,BA,AL,BA,PR,SA,SA,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,AL,AL,EX,EX,BA,BA,BB,AL,EX,EX,AL,CM,CM,CM,GL,CM,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,AL,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,AL,XX,XX,XX,EX,EX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,XX,SA,SA,SA,SA,SA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,XX,XX,XX,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,XX,XX,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,SA,XX,XX,XX,SA,SA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,XX,XX,AL,AL,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,XX,CM,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,XX,XX,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,BA,BA,AL,BA,BA,BA,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,BA,BA,XX,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,BA,BA,BA,BA,BA,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,AL,AL,AL,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,BA,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,CM,CM,CM,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,CM,AL,AL,AL,AL,AL,AL,CM,AL,AL,CM,CM,CM,AL,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,GL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,GL,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,XX,AL,XX,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,BB,AL,XX,BA,BA,BA,BA,BA,BA,BA,GL,BA,BA,BA,ZW,CM,ZWJ,CM,CM,BA,GL,BA,BA,B2,AI,AI,AL,QU,QU,OP,QU,QU,QU,OP,QU,AI,AI,AL,AL,IN,IN,IN,BA,BK,BK,CM,CM,CM,CM,CM,GL,PO,PO,PO,PO,PO,PO,PO,PO,AL,QU,QU,AI,NS,NS,AL,AL,AL,AL,IS,OP,CL,NS,NS,NS,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,BA,PO,BA,BA,BA,BA,AL,BA,BA,BA,WJ,AL,AL,AL,AL,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,XX,XX,AI,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,AI,AL,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,PR,PR,PR,PR,PR,PR,PR,PO,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PO,PR,PR,PR,PR,PO,PR,PR,PO,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,PR,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,PO,AL,AI,AL,AL,AL,PO,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,PR,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AL,AL,AL,AL,AL,AI,AL,AL,AI,AL,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AL,AL,AL,AL,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,XX,XX,XX,XX,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AI,AI,AL,AL,AL,AI,AI,AL,AL,AI,AL,AL,AL,AI,AL,AI,PR,PR,AL,AI,AL,AL,AL,AL,AI,AL,AL,AI,AI,AI,AI,AL,AL,AI,AL,AI,AL,AI,AI,AI,AI,AI,AI,AL,AI,AL,AL,AL,AL,AL,AI,AI,AI,AI,AL,AL,AL,AL,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,AI,AL,AL,AL,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AL,AL,AI,AI,AI,AI,AL,AL,AI,AI,AL,AL,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AL,AL,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,IN,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,OP,CL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,ID,ID,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,ID,ID,ID,ID,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AL,AL,AL,AL,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AL,AL,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AL,AI,AI,AI,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AL,AL,AI,AI,AL,AL,AL,AL,AI,AI,AL,AL,AL,AL,AI,AI,AI,AL,AL,AI,AL,AL,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,ID,ID,ID,ID,AL,AI,AI,AL,AL,AI,AL,AL,AL,AL,AI,AI,AL,AL,AL,AL,ID,ID,AI,AI,ID,AL,ID,ID,ID,EB,ID,ID,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,ID,ID,ID,AL,AL,AL,AL,AI,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AL,AI,AI,AI,AL,AI,ID,AI,AI,AL,AI,AI,AL,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,ID,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,ID,ID,ID,ID,ID,ID,ID,ID,ID,AI,AI,AI,AI,ID,AL,ID,ID,ID,AI,ID,ID,AI,AI,AI,ID,ID,AI,AI,ID,AI,AI,ID,ID,ID,AL,AI,AL,AL,AL,AL,AI,AI,ID,AI,AI,AI,AI,AI,AI,ID,ID,ID,ID,ID,AI,ID,ID,EB,ID,AI,AI,ID,ID,ID,ID,ID,AL,AL,AL,ID,ID,EB,EB,EB,EB,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AL,AL,AL,QU,QU,QU,QU,QU,QU,AL,EX,EX,ID,AL,AL,AL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,OP,CL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AI,AI,AI,AI,AI,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,AL,AL,XX,XX,XX,XX,XX,EX,BA,BA,BA,AL,EX,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,XX,XX,XX,XX,XX,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,AL,BA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,QU,QU,QU,QU,QU,QU,QU,QU,QU,QU,QU,QU,QU,QU,BA,BA,BA,BA,BA,BA,BA,BA,AL,BA,OP,BA,AL,AL,QU,QU,AL,AL,QU,QU,OP,CL,OP,CL,OP,CL,OP,CL,BA,BA,BA,BA,EX,AL,BA,BA,AL,BA,BA,AL,AL,AL,AL,AL,B2,B2,BA,BA,BA,AL,BA,BA,OP,BA,BA,BA,BA,BA,BA,BA,BA,AL,BA,AL,BA,BA,AL,AL,AL,EX,EX,OP,CL,OP,CL,OP,CL,OP,CL,BA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,XX,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,XX,XX,XX,XX,BA,CL,CL,ID,ID,NS,ID,ID,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,ID,ID,OP,CL,OP,CL,OP,CL,OP,CL,NS,OP,CL,CL,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,CM,CM,CM,CM,CM,CM,ID,ID,ID,ID,ID,CM,ID,ID,ID,ID,ID,NS,NS,ID,ID,ID,XX,CJ,ID,CJ,ID,CJ,ID,CJ,ID,CJ,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,CJ,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,CJ,ID,CJ,ID,CJ,ID,ID,ID,ID,ID,ID,CJ,ID,ID,ID,ID,ID,ID,CJ,CJ,XX,XX,CM,CM,NS,NS,NS,NS,ID,NS,CJ,ID,CJ,ID,CJ,ID,CJ,ID,CJ,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,CJ,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,CJ,ID,CJ,ID,CJ,ID,ID,ID,ID,ID,ID,CJ,ID,ID,ID,ID,ID,ID,CJ,CJ,ID,ID,ID,ID,NS,CJ,NS,NS,ID,XX,XX,XX,XX,XX,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,XX,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,ID,ID,ID,ID,ID,ID,ID,ID,AI,AI,AI,AI,AI,AI,AI,AI,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,NS,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,XX,XX,XX,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,BA,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,BA,EX,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,AL,BA,BA,BA,BA,BA,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,AL,AL,XX,AL,XX,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,AL,AL,AL,CM,AL,AL,AL,AL,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,AL,AL,AL,AL,CM,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,PO,AL,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,BB,BB,EX,EX,XX,XX,XX,XX,XX,XX,XX,XX,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,BA,BA,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,BB,AL,AL,CM,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,BA,BA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,JL,XX,XX,XX,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,BA,BA,BA,AL,AL,AL,AL,XX,AL,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,AL,AL,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,SA,SA,SA,SA,SA,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,CM,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,AL,BA,BA,BA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,SA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,SA,SA,SA,SA,SA,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,BA,BA,AL,AL,AL,CM,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,BA,CM,CM,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,XX,XX,H2,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H2,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H2,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H2,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,H3,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,JV,XX,XX,XX,XX,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,JT,XX,XX,XX,XX,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,SG,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,HL,CM,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,AL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,XX,HL,HL,HL,HL,HL,XX,HL,XX,HL,HL,XX,HL,HL,XX,HL,HL,HL,HL,HL,HL,HL,HL,HL,HL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CL,OP,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,PO,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,IS,CL,CL,IS,IS,EX,EX,OP,CL,IN,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,ID,ID,ID,ID,ID,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,OP,CL,ID,ID,OP,CL,ID,ID,ID,ID,ID,ID,ID,CL,ID,CL,XX,NS,NS,EX,EX,ID,OP,CL,OP,CL,OP,CL,ID,ID,ID,ID,ID,ID,ID,ID,XX,ID,PR,PO,ID,XX,XX,XX,XX,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,WJ,XX,EX,ID,ID,PR,PO,ID,ID,OP,CL,ID,ID,CL,ID,CL,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,NS,NS,ID,ID,ID,EX,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,OP,ID,CL,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,OP,ID,CL,ID,OP,CL,CL,OP,CL,CL,NS,ID,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,CJ,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,NS,NS,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,XX,XX,ID,ID,ID,ID,ID,ID,XX,XX,ID,ID,ID,ID,ID,ID,XX,XX,ID,ID,ID,ID,ID,ID,XX,XX,ID,ID,ID,XX,XX,XX,PO,PR,ID,ID,ID,PR,PR,XX,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CM,CM,CM,CB,AI,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,XX,AL,BA,BA,BA,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,XX,XX,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,BA,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,XX,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,XX,XX,XX,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,XX,XX,AL,XX,AL,AL,AL,AL,AL,AL,XX,AL,AL,XX,XX,XX,AL,XX,XX,AL,AL,AL,AL,AL,AL,XX,BA,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,BA,AL,CM,CM,CM,XX,CM,CM,XX,XX,XX,XX,XX,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,XX,XX,CM,CM,CM,XX,XX,XX,XX,CM,BA,BA,BA,BA,BA,BA,BA,BA,AL,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,CM,CM,XX,XX,XX,XX,AL,AL,AL,AL,AL,BA,BA,BA,BA,BA,BA,IN,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,XX,XX,XX,BA,BA,BA,BA,BA,BA,BA,AL,AL,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,CM,CM,BA,XX,XX,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,AL,AL,CM,CM,CM,CM,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,BA,BA,AL,AL,AL,AL,AL,XX,XX,CM,AL,AL,CM,CM,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,BA,BA,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,XX,XX,CM,CM,CM,CM,CM,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,BA,BA,BA,BA,AL,CM,CM,AL,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,CM,AL,BB,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,CM,AL,AL,AL,AL,BA,BA,AL,BA,CM,CM,CM,CM,AL,CM,CM,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,BB,AL,BA,BA,BA,CM,CM,CM,CM,CM,CM,CM,CM,BA,BA,AL,BA,BA,AL,CM,AL,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,XX,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,BA,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,XX,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,XX,AL,AL,XX,AL,AL,AL,AL,AL,XX,CM,CM,AL,CM,CM,AL,XX,XX,XX,XX,XX,XX,CM,XX,XX,XX,XX,XX,AL,AL,AL,CM,CM,XX,XX,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,BA,BA,BA,BA,AL,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,BA,BA,XX,AL,CM,AL,CM,CM,CM,CM,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,BB,BA,BA,EX,EX,AL,AL,AL,BA,BA,BA,BA,BA,BA,BA,BA,AL,AL,AL,AL,CM,CM,XX,XX,CM,BA,BA,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,BB,BB,BB,BB,BB,BB,BB,BB,BB,BB,BB,BB,BB,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,XX,XX,XX,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,SA,SA,BA,BA,BA,SA,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,XX,XX,AL,AL,AL,AL,XX,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,XX,CM,CM,XX,XX,CM,CM,CM,CM,AL,CM,CM,BA,BA,BA,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,CM,CM,CM,CM,CM,CM,CM,XX,XX,CM,CM,CM,CM,CM,CM,AL,BB,AL,CM,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,AL,CM,CM,CM,CM,BB,AL,BA,BA,BA,BA,BB,AL,CM,XX,XX,XX,XX,XX,XX,XX,XX,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,CM,BA,BA,BA,AL,BB,BB,BA,BA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,BB,BB,BB,BB,BB,BB,BB,BB,BB,BB,XX,XX,XX,XX,XX,XX,AL,BA,BA,BA,BA,BA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,BB,EX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,XX,XX,XX,CM,XX,CM,CM,XX,CM,CM,CM,CM,CM,CM,AL,CM,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,XX,AL,AL,XX,AL,AL,AL,AL,AL,AL,CM,CM,XX,CM,CM,CM,CM,CM,AL,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,CM,CM,CM,CM,AL,AL,XX,XX,XX,XX,XX,XX,XX,CM,CM,AL,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,CM,CM,CM,BA,BA,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,PO,PO,PO,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,BA,BA,BA,BA,BA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,OP,OP,OP,CL,CL,CL,AL,AL,CL,AL,AL,AL,OP,CL,OP,CL,AL,AL,AL,AL,AL,AL,AL,AL,AL,OP,CL,CL,AL,AL,AL,AL,GL,GL,GL,GL,GL,GL,GL,OP,CL,GL,GL,GL,OP,CL,OP,CL,CM,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,CM,CM,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,BA,BA,CM,CM,CM,CM,CM,BA,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,BA,BA,BA,AL,AL,AL,AL,AL,AL,BA,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,AL,AL,AL,AL,AL,AL,AL,BA,BA,AL,AL,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,XX,XX,CM,NS,NS,NS,NS,GL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CJ,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CJ,CJ,CJ,XX,XX,CJ,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,CJ,CJ,CJ,CJ,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,CM,CM,BA,AL,AL,AL,AL,AL,CM,CM,CM,CM,CM,AL,AL,AL,CM,CM,CM,AL,AL,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,CM,CM,CM,AL,AL,CM,CM,CM,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,XX,XX,AL,AL,XX,XX,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,AL,XX,AL,AL,AL,AL,AL,XX,AL,XX,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,AL,AL,AL,AL,AL,CM,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,AL,AL,BA,BA,BA,BA,AL,XX,XX,XX,XX,XX,AL,AL,AL,AL,AL,AL,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,CM,CM,XX,XX,CM,CM,CM,CM,CM,XX,CM,CM,XX,CM,CM,CM,CM,CM,XX,XX,XX,XX,XX,CM,CM,CM,CM,CM,CM,CM,AL,AL,AL,AL,AL,AL,AL,XX,XX,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,CM,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,XX,PR,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,XX,AL,AL,XX,AL,AL,AL,AL,CM,CM,CM,CM,CM,CM,CM,AL,XX,XX,XX,XX,NU,NU,NU,NU,NU,NU,NU,NU,NU,NU,XX,XX,XX,XX,OP,OP,PO,AL,AL,AL,AL,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,AL,AL,XX,AL,XX,XX,AL,XX,AL,AL,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,XX,AL,XX,AL,XX,XX,XX,XX,AL,XX,XX,XX,XX,AL,XX,AL,XX,AL,XX,AL,AL,AL,XX,AL,AL,XX,AL,XX,XX,AL,XX,AL,XX,AL,XX,AL,XX,AL,AL,XX,AL,XX,XX,AL,AL,AL,AL,XX,AL,AL,AL,AL,XX,AL,AL,AL,AL,XX,AL,XX,AL,AL,AL,XX,AL,AL,AL,AL,AL,XX,AL,AL,AL,AL,AL,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,ID,ID,ID,AI,AI,AI,AI,AI,AI,AI,AI,AI,AI,AL,AL,AL,ID,ID,ID,ID,ID,ID,RI,RI,RI,RI,RI,RI,RI,RI,RI,RI,RI,RI,RI,RI,RI,RI,ID,ID,ID,ID,ID,EB,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,AL,AL,ID,ID,ID,ID,ID,AL,ID,ID,ID,EB,EB,EB,ID,ID,EB,ID,ID,EB,EB,EB,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,EM,EM,EM,EM,EM,ID,ID,EB,EB,ID,ID,EB,EB,EB,EB,EB,EB,EB,EB,EB,EB,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,EB,EB,EB,EB,EB,EB,EB,EB,EB,EB,ID,ID,ID,EB,ID,ID,ID,EB,EB,EB,ID,EB,EB,EB,ID,ID,ID,ID,ID,ID,ID,EB,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,AL,ID,AL,ID,AL,ID,ID,ID,ID,ID,EB,ID,ID,ID,ID,AL,AL,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,AL,AL,AL,AL,AL,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,EB,EB,ID,ID,ID,ID,EB,ID,ID,ID,ID,ID,EB,ID,ID,ID,ID,EB,EB,ID,ID,ID,ID,ID,ID,ID,ID,ID,AL,AL,AL,AL,AL,AL,AL,AL,ID,ID,ID,ID,AL,AL,AL,AL,AL,AL,ID,ID,ID,ID,ID,ID,EB,EB,EB,ID,ID,ID,EB,EB,EB,EB,EB,AL,AL,AL,AL,AL,AL,QU,QU,QU,NS,NS,NS,AL,AL,AL,AL,ID,ID,ID,ID,EB,EB,EB,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,EB,ID,ID,ID,AL,AL,AL,AL,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,ID,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,AL,EB,ID,ID,EB,EB,EB,EB,EB,EB,EB,EB,EB,EB,ID,ID,EB,EB,EB,ID,ID,ID,ID,ID,EB,EB,ID,EB,EB,ID,EB,ID,ID,ID,ID,EB,EB,EB,EB,EB,EB,EB,EB,EB,EB,EB,EB,EB,ID,ID,]; - -static PAIR_TABLE: [[u8; 44]; 53] = [[192,193,194,221,196,221,198,199,200,201,221,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,221,221,212,223,224,225,226,227,228,229,230,231,232,221,221,235,],[192,193,2,221,196,221,198,199,200,201,221,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,221,221,212,223,224,225,226,227,228,229,230,231,232,221,221,235,],[192,193,194,221,196,221,198,199,200,201,221,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,221,221,212,223,224,225,226,227,228,229,230,231,232,221,221,235,],[0,1,2,3,4,29,6,7,8,9,3,139,12,141,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[192,193,194,221,196,221,198,199,200,201,221,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,221,221,212,223,224,225,226,227,228,229,230,231,232,221,221,235,],[0,1,2,29,4,29,6,7,8,9,29,139,12,141,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,6,4,29,6,7,8,9,6,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,31,32,33,34,35,36,37,38,39,40,29,29,235,],[0,1,2,157,4,157,134,7,136,45,157,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,157,157,148,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,8,4,29,6,7,8,9,8,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,31,32,33,34,35,36,37,38,39,40,29,29,235,],[0,1,2,157,4,157,6,7,136,9,157,139,140,141,142,143,16,17,18,147,148,149,150,23,152,153,154,27,157,157,148,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,10,4,29,6,7,8,9,10,139,12,141,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,11,4,157,6,7,8,50,11,11,12,141,14,143,16,17,18,19,20,149,22,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,12,4,157,6,7,136,9,12,139,12,141,14,143,16,17,18,19,20,149,22,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,13,4,29,6,7,8,9,13,11,12,13,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,31,32,33,34,35,36,37,38,39,40,29,29,235,],[0,1,2,14,4,157,6,7,136,9,14,139,12,141,14,143,16,17,18,19,20,149,22,23,24,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,15,4,157,6,7,8,9,15,139,140,141,142,143,16,17,18,147,148,149,22,23,152,153,154,27,157,157,148,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,16,4,157,6,7,8,48,16,139,12,141,14,143,16,17,18,19,20,149,22,23,152,25,26,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,17,4,29,6,7,8,49,17,139,12,141,14,143,16,17,18,19,20,149,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,18,4,157,6,7,8,9,18,139,12,141,14,143,16,17,18,19,20,149,22,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,19,4,157,6,7,8,9,19,139,12,141,14,143,16,17,18,19,20,149,22,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,20,4,157,6,7,8,9,20,139,12,141,14,143,16,17,18,19,20,149,22,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,21,4,29,6,7,8,46,21,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,31,32,33,34,35,36,37,38,39,40,29,29,235,],[0,1,2,22,4,29,6,7,8,47,22,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,31,32,33,34,35,36,37,38,39,40,29,29,235,],[0,1,2,23,4,29,6,7,8,9,23,139,12,141,14,143,16,17,18,19,20,149,22,23,24,153,154,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,24,4,29,6,7,8,9,24,139,12,141,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,25,4,29,6,7,8,9,25,139,12,141,14,143,16,17,18,19,20,21,22,23,24,153,154,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,26,4,29,6,7,8,9,26,139,12,141,14,143,16,17,18,19,20,21,22,23,24,153,154,27,29,29,20,31,32,33,34,35,36,37,38,39,168,29,29,235,],[0,1,2,27,4,157,6,7,8,9,27,139,12,141,14,143,16,17,18,19,20,149,22,23,24,153,154,27,157,157,20,159,160,161,162,35,164,165,166,167,168,157,157,235,],[0,1,2,29,4,29,6,7,8,9,29,139,12,141,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,29,4,29,6,7,8,9,29,139,12,141,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,20,4,157,6,7,8,9,20,139,12,141,14,143,16,17,18,19,20,149,22,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,31,4,157,6,7,8,9,31,139,12,141,14,143,16,17,18,19,20,149,22,23,152,25,154,27,157,157,20,159,32,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,32,4,157,6,7,8,9,32,139,12,141,14,143,16,17,18,19,20,149,22,23,152,25,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,33,4,157,6,7,8,9,33,139,12,141,14,143,16,17,18,19,20,149,22,23,152,25,154,27,157,157,20,159,160,161,162,163,164,165,38,39,168,157,157,235,],[0,1,2,34,4,157,6,7,8,9,34,139,12,141,14,143,16,17,18,19,20,149,22,23,152,25,154,27,157,157,20,159,160,161,162,163,164,165,166,39,168,157,157,235,],[0,1,2,35,4,29,6,7,8,9,35,139,51,141,51,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,36,4,157,6,7,8,9,36,139,12,141,14,143,16,17,18,19,20,149,22,23,152,25,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,37,4,157,6,7,8,9,37,139,12,141,14,143,16,17,18,19,20,149,22,23,152,25,154,27,157,157,20,159,160,33,34,163,164,37,38,167,168,157,157,235,],[0,1,2,38,4,157,6,7,8,9,38,139,12,141,14,143,16,17,18,19,20,149,22,23,152,25,154,27,157,157,20,159,160,161,162,163,164,165,38,39,168,157,157,235,],[0,1,2,39,4,157,6,7,8,9,39,139,12,141,14,143,16,17,18,19,20,149,22,23,152,25,154,27,157,157,20,159,160,161,162,163,164,165,166,39,168,157,157,235,],[0,1,2,40,4,157,6,7,8,9,40,139,12,141,14,143,16,17,18,19,20,149,22,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,52,157,157,235,],[0,1,2,29,4,29,6,7,8,9,29,139,12,141,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,29,4,29,6,7,8,9,29,139,12,141,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,159,160,161,162,35,164,165,166,167,168,29,29,235,],[0,1,2,157,4,157,6,7,136,9,157,139,12,141,14,143,16,17,18,19,20,149,22,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,29,4,29,6,7,8,9,29,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,31,32,33,34,35,36,37,38,39,40,29,29,43,],[0,1,2,157,4,157,134,7,136,45,157,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,157,157,148,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,29,4,29,6,7,8,46,29,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,31,32,33,34,35,36,37,38,39,40,29,29,235,],[0,1,2,157,4,157,6,7,136,47,157,139,140,141,142,143,16,17,18,147,148,21,150,23,152,153,154,27,157,157,148,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,157,4,157,6,7,136,48,157,139,140,141,142,143,16,17,18,147,20,149,150,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,157,4,157,6,7,136,49,157,139,140,141,142,143,16,17,18,147,20,149,150,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,157,4,157,6,7,136,50,157,11,140,141,142,143,16,17,18,147,148,149,150,23,152,153,154,27,157,157,148,159,160,161,162,163,164,165,166,167,168,157,157,235,],[0,1,2,51,4,29,6,7,8,9,51,11,12,13,14,143,16,17,18,19,20,21,22,23,24,25,26,27,29,29,20,31,32,33,34,35,36,37,38,39,40,29,29,235,],[0,1,2,52,4,157,6,7,8,9,52,139,12,141,14,143,16,17,18,19,20,149,22,23,152,153,154,27,157,157,20,159,160,161,162,163,164,165,166,167,168,157,157,235,],]; - - fn is_safe_pair(a: BreakClass, b: BreakClass) -> bool { - !matches!((a, b), (CM, CM)|(SP, CM)|(ZWJ, CM)|(BA, CM)|(HY, CM)|(RI, CM)|(CM, SG)|(SP, SG)|(ZWJ, SG)|(BA, SG)|(HY, SG)|(SP, WJ)|(CM, GL)|(SP, GL)|(ZWJ, GL)|(BA, GL)|(HY, GL)|(CM, SP)|(SP, SP)|(ZWJ, SP)|(CM, ZWJ)|(SP, ZWJ)|(ZWJ, ZWJ)|(BA, ZWJ)|(HY, ZWJ)|(RI, ZWJ)|(CM, B2)|(SP, B2)|(ZWJ, B2)|(BA, B2)|(HY, B2)|(CM, BA)|(SP, BA)|(ZWJ, BA)|(CM, BB)|(SP, BB)|(ZWJ, BB)|(BA, BB)|(HY, BB)|(CM, HY)|(SP, HY)|(ZWJ, HY)|(CM, CB)|(SP, CB)|(ZWJ, CB)|(SP, CL)|(SP, CP)|(SP, EX)|(CM, IN)|(SP, IN)|(ZWJ, IN)|(CM, NS)|(SP, NS)|(ZWJ, NS)|(CM, OP)|(SP, OP)|(ZWJ, OP)|(BA, OP)|(HY, OP)|(SP, QU)|(SP, IS)|(CM, NU)|(SP, NU)|(ZWJ, NU)|(BA, NU)|(CM, PO)|(SP, PO)|(ZWJ, PO)|(BA, PO)|(HY, PO)|(CM, PR)|(SP, PR)|(ZWJ, PR)|(BA, PR)|(HY, PR)|(SP, SY)|(CM, AI)|(SP, AI)|(ZWJ, AI)|(BA, AI)|(HY, AI)|(CM, AL)|(SP, AL)|(ZWJ, AL)|(BA, AL)|(HY, AL)|(CM, CJ)|(SP, CJ)|(ZWJ, CJ)|(CM, EB)|(SP, EB)|(ZWJ, EB)|(BA, EB)|(HY, EB)|(CM, EM)|(SP, EM)|(ZWJ, EM)|(BA, EM)|(HY, EM)|(CM, H2)|(SP, H2)|(ZWJ, H2)|(BA, H2)|(HY, H2)|(CM, H3)|(SP, H3)|(ZWJ, H3)|(BA, H3)|(HY, H3)|(CM, HL)|(SP, HL)|(ZWJ, HL)|(BA, HL)|(HY, HL)|(CM, ID)|(SP, ID)|(ZWJ, ID)|(BA, ID)|(HY, ID)|(CM, JL)|(SP, JL)|(ZWJ, JL)|(BA, JL)|(HY, JL)|(CM, JV)|(SP, JV)|(ZWJ, JV)|(BA, JV)|(HY, JV)|(CM, JT)|(SP, JT)|(ZWJ, JT)|(BA, JT)|(HY, JT)|(CM, RI)|(SP, RI)|(ZWJ, RI)|(BA, RI)|(HY, RI)|(RI, RI)|(CM, SA)|(SP, SA)|(ZWJ, SA)|(BA, SA)|(HY, SA)|(CM, XX)|(SP, XX)|(ZWJ, XX)|(BA, XX)|(HY, XX)) - } diff --git a/third_party/rust/uniffi-example-arithmetic/.cargo-checksum.json b/third_party/rust/uniffi-example-arithmetic/.cargo-checksum.json index 33a544782109..24e445a094c6 100644 --- a/third_party/rust/uniffi-example-arithmetic/.cargo-checksum.json +++ b/third_party/rust/uniffi-example-arithmetic/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"359cffb76e0eac82aeec6a667f7670fa4b88346c2dd7c17febe71731fd6df58b","build.rs":"7d98b49c1d9c868c4199f0417eaa017ab459cdd536e9a29851d5f707941f9ead","src/arithmetic.udl":"8554c6907ece627645f6b896f71430e5412bf19b0ac6becf63eb9a69868d0f7a","src/lib.rs":"c454193443e92d49f997c760f4131192fb66bf213bbac1710c1ebde19e765e5d","tests/bindings/test_arithmetic.kts":"e0e9347755db4e18f70b1b74c2d5a4aa328373015090ed959b46d65c2a205d92","tests/bindings/test_arithmetic.py":"3e41d69e21e96a6830197c760f3b7bddd754edc0c5515b7bd33b79cccb10f941","tests/bindings/test_arithmetic.rb":"ea0fdce0a4c7b557b427db77521da05240cd6e87d60a128ac2307fab3bbbc76d","tests/bindings/test_arithmetic.swift":"455b87d95fc690af9c35f9e43676e9c855dedddd2fc1c9e1cbaa6a02835c2d4c","tests/test_generated_bindings.rs":"26b92d6b3e648f6fadd4182cbdba4f412b73da48a789785fd98cd486b29abf05","uniffi.toml":"a2d4f46fa51dc1be1e8bcdf67ec13223637fc1b6c6437455cf53c2dae065fb45"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"056d32277bd81040868270ae29d54b3d59ba08833cc307e8aee14a61b914d658","build.rs":"7d98b49c1d9c868c4199f0417eaa017ab459cdd536e9a29851d5f707941f9ead","src/arithmetic.udl":"8554c6907ece627645f6b896f71430e5412bf19b0ac6becf63eb9a69868d0f7a","src/lib.rs":"c454193443e92d49f997c760f4131192fb66bf213bbac1710c1ebde19e765e5d","tests/bindings/test_arithmetic.kts":"e0e9347755db4e18f70b1b74c2d5a4aa328373015090ed959b46d65c2a205d92","tests/bindings/test_arithmetic.py":"3e41d69e21e96a6830197c760f3b7bddd754edc0c5515b7bd33b79cccb10f941","tests/bindings/test_arithmetic.rb":"ea0fdce0a4c7b557b427db77521da05240cd6e87d60a128ac2307fab3bbbc76d","tests/bindings/test_arithmetic.swift":"455b87d95fc690af9c35f9e43676e9c855dedddd2fc1c9e1cbaa6a02835c2d4c","tests/test_generated_bindings.rs":"26b92d6b3e648f6fadd4182cbdba4f412b73da48a789785fd98cd486b29abf05","uniffi.toml":"a2d4f46fa51dc1be1e8bcdf67ec13223637fc1b6c6437455cf53c2dae065fb45"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-arithmetic/Cargo.toml b/third_party/rust/uniffi-example-arithmetic/Cargo.toml index 52f08bb9f62c..4efddceb0a70 100644 --- a/third_party/rust/uniffi-example-arithmetic/Cargo.toml +++ b/third_party/rust/uniffi-example-arithmetic/Cargo.toml @@ -28,15 +28,15 @@ crate-type = [ thiserror = "1.0" [dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" [dev-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["bindgen-tests"] [build-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["build"] diff --git a/third_party/rust/uniffi-example-geometry/.cargo-checksum.json b/third_party/rust/uniffi-example-geometry/.cargo-checksum.json index 52b8ef33dbc0..43ff27846095 100644 --- a/third_party/rust/uniffi-example-geometry/.cargo-checksum.json +++ b/third_party/rust/uniffi-example-geometry/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"2d2c1ec66f7e2aaa4553b5338e68a7b64d68b84152547e1ccc4eeb019ca97103","build.rs":"fc5da645c8862e15f3b6879db179a1e5eec6161dc1cfbf95a4db9daf107a133f","src/geometry.udl":"7da7a6ec080c7117ec3c25206e23f9ed436e60b1a26fba34f991547680443550","src/lib.rs":"f9d004c97efb1a719368169f0aab181f27439eda3520c1afaca2420433226682","tests/bindings/test_geometry.kts":"e537185e3c699df1c0468525700e8a38f9a504b2a663c38442146b951e38e9a7","tests/bindings/test_geometry.py":"600e74ba0eba4e35d824c8f6d5bd5a2120a470017e8465c32d1e954a1939d323","tests/bindings/test_geometry.rb":"651de70af595f8b52ef030a03356939e8c1d0b40e44b4155b45d565d1d1dcbed","tests/bindings/test_geometry.swift":"a61fec6bfe16020809e20e4da372748c24366767138c5672a0bfff85c4b62d78","tests/test_generated_bindings.rs":"ff8fc093ccb6ee3ee2235c09276c7bb87234ad143667429cb721e46379577f3d"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"caa1fbdbfdf87670cf571dda2e693e8bc9ba38a0a8fbf803014664e84cde3213","build.rs":"fc5da645c8862e15f3b6879db179a1e5eec6161dc1cfbf95a4db9daf107a133f","src/geometry.udl":"7da7a6ec080c7117ec3c25206e23f9ed436e60b1a26fba34f991547680443550","src/lib.rs":"f9d004c97efb1a719368169f0aab181f27439eda3520c1afaca2420433226682","tests/bindings/test_geometry.kts":"e537185e3c699df1c0468525700e8a38f9a504b2a663c38442146b951e38e9a7","tests/bindings/test_geometry.py":"3ea483b8a4fbe13aefa6641177ae149f75f734bc32bf0da533b97c1abf3dc317","tests/bindings/test_geometry.rb":"17c2fe8a7b477419a6646983dd88f1b07a0304b58a568c03e9bfa640d5b2df5c","tests/bindings/test_geometry.swift":"a61fec6bfe16020809e20e4da372748c24366767138c5672a0bfff85c4b62d78","tests/test_generated_bindings.rs":"ff8fc093ccb6ee3ee2235c09276c7bb87234ad143667429cb721e46379577f3d"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-geometry/Cargo.toml b/third_party/rust/uniffi-example-geometry/Cargo.toml index b9c8a0beb69b..b9fe377732fd 100644 --- a/third_party/rust/uniffi-example-geometry/Cargo.toml +++ b/third_party/rust/uniffi-example-geometry/Cargo.toml @@ -25,15 +25,15 @@ crate-type = [ ] [dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" [dev-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["bindgen-tests"] [build-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["build"] diff --git a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.py b/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.py index fd6772be2490..a40e2af6ecab 100644 --- a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.py +++ b/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.py @@ -1,10 +1,10 @@ from geometry import * -ln1 = Line(start=Point(coord_x=0, coord_y=0), end=Point(coord_x=1, coord_y=2)) -ln2 = Line(start=Point(coord_x=1, coord_y=1), end=Point(coord_x=2, coord_y=2)) +ln1 = Line(Point(0,0), Point(1,2)) +ln2 = Line(Point(1,1), Point(2,2)) assert gradient(ln1) == 2 assert gradient(ln2) == 1 -assert intersection(ln1, ln2) == Point(coord_x=0, coord_y=0) +assert intersection(ln1, ln2) == Point(0, 0) assert intersection(ln1, ln1) is None diff --git a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.rb b/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.rb index 90fdff684e4d..8b1280d82398 100644 --- a/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.rb +++ b/third_party/rust/uniffi-example-geometry/tests/bindings/test_geometry.rb @@ -6,11 +6,11 @@ require 'geometry' include Test::Unit::Assertions include Geometry -ln1 = Line.new(start: Point.new(coord_x: 0.0, coord_y: 0.0), _end: Point.new(coord_x: 1.0, coord_y: 2.0)) -ln2 = Line.new(start: Point.new(coord_x: 1.0, coord_y: 1.0), _end: Point.new(coord_x: 2.0, coord_y: 2.0)) +ln1 = Line.new(Point.new(0.0, 0.0), Point.new(1.0, 2.0)) +ln2 = Line.new(Point.new(1.0, 1.0), Point.new(2.0, 2.0)) assert_equal Geometry.gradient(ln1), 2 assert_equal Geometry.gradient(ln2), 1 -assert_equal Geometry.intersection(ln1, ln2), Point.new(coord_x: 0, coord_y: 0) +assert_equal Geometry.intersection(ln1, ln2), Point.new(0, 0) assert Geometry.intersection(ln1, ln1).nil? diff --git a/third_party/rust/uniffi-example-rondpoint/.cargo-checksum.json b/third_party/rust/uniffi-example-rondpoint/.cargo-checksum.json index 2f1f261a1327..87e0d96e40d9 100644 --- a/third_party/rust/uniffi-example-rondpoint/.cargo-checksum.json +++ b/third_party/rust/uniffi-example-rondpoint/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c0706abf631a178bfbc2e53b0b714d4a7b73059c46e1326efa4f52d235dc05f5","build.rs":"ba88cce38ecd3321a7a93623755e3339e255360a7f946d3779ded804662c081a","src/lib.rs":"740d70ab5ca22eefcc291a56a9e4ed84e9669f4cfe3890e7d79bc56ae4b991a3","src/rondpoint.udl":"c903cb8c95b3ec1b103350857c3c3bc428bfd90c86a6c48089db9e0fc6e41eb5","tests/bindings/test_rondpoint.kts":"4aac8353278807f4add95c81f4c6c61187204b9767f882fd64872ed8ac1f6451","tests/bindings/test_rondpoint.py":"af25a56c35da9a934fb9f098c25f57329c53d461be378e4c5089b12a45efa28b","tests/bindings/test_rondpoint.rb":"d4b4523084534266ea7ef3161021b9903cb8d7a75cf4624c59055af9f02d22f9","tests/bindings/test_rondpoint.swift":"fa806e7e09c22ed44496658f6e0781765447bbdd250d7adf4b1152248ed70e69","tests/test_generated_bindings.rs":"5464f89e91c458f164b83a454c6df67a2953873e8a785a4720a2253d843f88e5"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"e945bedc4897a588199714e71d6210a77d051925af39b345e605fc58fb782b50","build.rs":"ba88cce38ecd3321a7a93623755e3339e255360a7f946d3779ded804662c081a","src/lib.rs":"740d70ab5ca22eefcc291a56a9e4ed84e9669f4cfe3890e7d79bc56ae4b991a3","src/rondpoint.udl":"c903cb8c95b3ec1b103350857c3c3bc428bfd90c86a6c48089db9e0fc6e41eb5","tests/bindings/test_rondpoint.kts":"4aac8353278807f4add95c81f4c6c61187204b9767f882fd64872ed8ac1f6451","tests/bindings/test_rondpoint.py":"d618274170af767f8a5614a2565ea698b26ea3e1a222d5c110e7b2d00763e73b","tests/bindings/test_rondpoint.rb":"9cc49df311823d6caedbe7b05ff8c4da6329063c2ce16810192aaaa7edcdf5f5","tests/bindings/test_rondpoint.swift":"fa806e7e09c22ed44496658f6e0781765447bbdd250d7adf4b1152248ed70e69","tests/test_generated_bindings.rs":"5464f89e91c458f164b83a454c6df67a2953873e8a785a4720a2253d843f88e5"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-rondpoint/Cargo.toml b/third_party/rust/uniffi-example-rondpoint/Cargo.toml index 44d9628df496..64232cf2d204 100644 --- a/third_party/rust/uniffi-example-rondpoint/Cargo.toml +++ b/third_party/rust/uniffi-example-rondpoint/Cargo.toml @@ -25,15 +25,15 @@ crate-type = [ ] [dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" [dev-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["bindgen-tests"] [build-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["build"] diff --git a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py b/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py index 0b47c0fa5a28..ecfcc1e527d6 100644 --- a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py +++ b/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py @@ -2,7 +2,7 @@ import sys import ctypes from rondpoint import * -dico = Dictionnaire(un=Enumeration.DEUX, deux=True, petit_nombre=0, gros_nombre=123456789) +dico = Dictionnaire(Enumeration.DEUX, True, 0, 123456789) copyDico = copie_dictionnaire(dico) assert dico == copyDico diff --git a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.rb b/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.rb index faa4062019be..0121f6e0f91a 100644 --- a/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.rb +++ b/third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.rb @@ -6,12 +6,7 @@ require 'rondpoint' include Test::Unit::Assertions include Rondpoint -dico = Dictionnaire.new( - un: Enumeration::DEUX, - deux: true, - petit_nombre: 0, - gros_nombre: 123_456_789 -) +dico = Dictionnaire.new Enumeration::DEUX, true, 0, 123_456_789 assert_equal dico, Rondpoint.copie_dictionnaire(dico) diff --git a/third_party/rust/uniffi-example-sprites/.cargo-checksum.json b/third_party/rust/uniffi-example-sprites/.cargo-checksum.json index 8a890fb65cf3..3542d7cfd71f 100644 --- a/third_party/rust/uniffi-example-sprites/.cargo-checksum.json +++ b/third_party/rust/uniffi-example-sprites/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"94385b28fdc7e33b7019fada486124c027d29b3d2b11b57e8d488658386f7974","build.rs":"7e9d92d7c8fc17b359a29117b137ffc4d32f6c10b450d03e30a396339d8c9099","src/lib.rs":"d7984c0c10011b1bd939bce71dae7437ebb9090583b5d1b1cc133c2e5f60ab66","src/sprites.udl":"bfd35f04ba0549301189dfb8fc45b0f39bad00956c324f33be0e845fb7ff78aa","tests/bindings/test_sprites.kts":"06ed115325f37ce59ed6f33e2d651cd2aa352fddcc644580f62a6da6ca075844","tests/bindings/test_sprites.py":"f976f2be7ab8b88e8b84def760a849c0d98f4c7b481f054f92b566325d78d52d","tests/bindings/test_sprites.rb":"009d545bb7167b7218211430cfaeeb143cc30617eedcf3e51baafe752ad43241","tests/bindings/test_sprites.swift":"b2c0a6f4d5edfd7de7c2ba77b838865ffda153a6f364f273456175192d3e6e00","tests/test_generated_bindings.rs":"9a22d693c97fc6d90031cc60f61ece1d9279165ad6a92c9fe937448e126e8de6"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"e2d06b68b0865f390496bffce512d19d5fc473b64ff23c705daabb4169b8301c","build.rs":"7e9d92d7c8fc17b359a29117b137ffc4d32f6c10b450d03e30a396339d8c9099","src/lib.rs":"d7984c0c10011b1bd939bce71dae7437ebb9090583b5d1b1cc133c2e5f60ab66","src/sprites.udl":"bfd35f04ba0549301189dfb8fc45b0f39bad00956c324f33be0e845fb7ff78aa","tests/bindings/test_sprites.kts":"06ed115325f37ce59ed6f33e2d651cd2aa352fddcc644580f62a6da6ca075844","tests/bindings/test_sprites.py":"2e6ce838cfb387586257703c3500062438e840dd7ae57d185cdc244dc0745b8f","tests/bindings/test_sprites.rb":"6289a1833c7c8f4583ee4f0488d680de2ee46cfb203095a9b66d7234e2f07d53","tests/bindings/test_sprites.swift":"b2c0a6f4d5edfd7de7c2ba77b838865ffda153a6f364f273456175192d3e6e00","tests/test_generated_bindings.rs":"9a22d693c97fc6d90031cc60f61ece1d9279165ad6a92c9fe937448e126e8de6"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-sprites/Cargo.toml b/third_party/rust/uniffi-example-sprites/Cargo.toml index c6dc9d1f4b4a..6caed17ab102 100644 --- a/third_party/rust/uniffi-example-sprites/Cargo.toml +++ b/third_party/rust/uniffi-example-sprites/Cargo.toml @@ -25,15 +25,15 @@ crate-type = [ ] [dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" [dev-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["bindgen-tests"] [build-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["build"] diff --git a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.py b/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.py dissimilarity index 88% index d04742e076be..5142c2fc42e9 100644 --- a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.py +++ b/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.py @@ -1,17 +1,17 @@ -from sprites import * - -sempty = Sprite(None) -assert sempty.get_position() == Point(x=0, y=0) - -s = Sprite(Point(x=0, y=1)) -assert s.get_position() == Point(x=0, y=1) - -s.move_to(Point(x=1, y=2)) -assert s.get_position() == Point(x=1, y=2) - -s.move_by(Vector(dx=-4, dy=2)) -assert s.get_position() == Point(x=-3, y=4) - -srel = Sprite.new_relative_to(Point(x=0, y=1), Vector(dx=1, dy=1.5)) -assert srel.get_position() == Point(x=1, y=2.5) - +from sprites import * + +sempty = Sprite(None) +assert sempty.get_position() == Point(0, 0) + +s = Sprite(Point(0, 1)) +assert s.get_position() == Point(0, 1) + +s.move_to(Point(1, 2)) +assert s.get_position() == Point(1, 2) + +s.move_by(Vector(-4, 2)) +assert s.get_position() == Point(-3, 4) + +srel = Sprite.new_relative_to(Point(0, 1), Vector(1, 1.5)) +assert srel.get_position() == Point(1, 2.5) + diff --git a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.rb b/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.rb dissimilarity index 75% index fa73043979ea..9d79b57026f9 100644 --- a/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.rb +++ b/third_party/rust/uniffi-example-sprites/tests/bindings/test_sprites.rb @@ -1,22 +1,22 @@ -# frozen_string_literal: true - -require 'test/unit' -require 'sprites' - -include Test::Unit::Assertions -include Sprites - -sempty = Sprite.new(nil) -assert_equal sempty.get_position, Point.new(x: 0, y: 0) - -s = Sprite.new(Point.new(x: 0, y: 1)) -assert_equal s.get_position, Point.new(x: 0, y: 1) - -s.move_to(Point.new(x: 1, y: 2)) -assert_equal s.get_position, Point.new(x: 1, y: 2) - -s.move_by(Vector.new(dx: -4, dy: 2)) -assert_equal s.get_position, Point.new(x: -3, y: 4) - -srel = Sprite.new_relative_to(Point.new(x: 0, y: 1), Vector.new(dx: 1, dy: 1.5)) -assert_equal srel.get_position, Point.new(x: 1, y: 2.5) +# frozen_string_literal: true + +require 'test/unit' +require 'sprites' + +include Test::Unit::Assertions +include Sprites + +sempty = Sprite.new(nil) +assert_equal sempty.get_position, Point.new(0, 0) + +s = Sprite.new(Point.new(0, 1)) +assert_equal s.get_position, Point.new(0, 1) + +s.move_to(Point.new(1, 2)) +assert_equal s.get_position, Point.new(1, 2) + +s.move_by(Vector.new(-4, 2)) +assert_equal s.get_position, Point.new(-3, 4) + +srel = Sprite.new_relative_to(Point.new(0, 1), Vector.new(1, 1.5)) +assert_equal srel.get_position, Point.new(1, 2.5) diff --git a/third_party/rust/uniffi-example-todolist/.cargo-checksum.json b/third_party/rust/uniffi-example-todolist/.cargo-checksum.json index 6b3a53fc5ed9..a0bf1d826c81 100644 --- a/third_party/rust/uniffi-example-todolist/.cargo-checksum.json +++ b/third_party/rust/uniffi-example-todolist/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"9b182bf2d363240fe1f7b41c73da4bde96d87562812885e4f3175cb6b92ea56b","build.rs":"709d073560a66876d2b975f5145a2dc36e1e3420d79328c8b62666526cae5b2d","src/lib.rs":"ccf6851beb2a3e481541dd8a3c3e3d2fbd513a410eef820221942098212a8184","src/todolist.udl":"1f8a24049c2340b9184e95facfc191ecdcb91541729ae7f20b4625d67685f13c","tests/bindings/test_todolist.kts":"f3d29b48e0193563fc4f131d91ea697f758174dcdb80ea554f233949e575bf55","tests/bindings/test_todolist.py":"8ea1377fe336adaf4cade0fe073ae5825c3b38c63e46b7f4e92b87c0fe57c036","tests/bindings/test_todolist.rb":"e8840eb81477048718a56c5fa02c0fb2e28cf0a598a20c9393ba2262d6ffb89b","tests/bindings/test_todolist.swift":"d1911b85fe0c8c0b42e5421b5af5d7359c9a65bba477d23560eb4b0f52e80662","tests/test_generated_bindings.rs":"46ef1fbedaac0c4867812ef2632a641eab36ab0ee12f5757567dd037aeddcbd3"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"cb308f7bd5299ed45a3bd516390e21e28d0b02a1913e25917e30e9b8ebe084e3","build.rs":"709d073560a66876d2b975f5145a2dc36e1e3420d79328c8b62666526cae5b2d","src/lib.rs":"ccf6851beb2a3e481541dd8a3c3e3d2fbd513a410eef820221942098212a8184","src/todolist.udl":"1f8a24049c2340b9184e95facfc191ecdcb91541729ae7f20b4625d67685f13c","tests/bindings/test_todolist.kts":"f3d29b48e0193563fc4f131d91ea697f758174dcdb80ea554f233949e575bf55","tests/bindings/test_todolist.py":"f7430af9347df0daa954d38bc2203ce400affbb9a53fced4bb67a6796afa0664","tests/bindings/test_todolist.rb":"6524b5271a9cc0e2d78ca9f86ccb6973889926688a0843b4505a4f62d48f6dcb","tests/bindings/test_todolist.swift":"d1911b85fe0c8c0b42e5421b5af5d7359c9a65bba477d23560eb4b0f52e80662","tests/test_generated_bindings.rs":"46ef1fbedaac0c4867812ef2632a641eab36ab0ee12f5757567dd037aeddcbd3"},"package":null} \ No newline at end of file diff --git a/third_party/rust/uniffi-example-todolist/Cargo.toml b/third_party/rust/uniffi-example-todolist/Cargo.toml index cf4de491cd7a..9421e726a0ca 100644 --- a/third_party/rust/uniffi-example-todolist/Cargo.toml +++ b/third_party/rust/uniffi-example-todolist/Cargo.toml @@ -29,15 +29,15 @@ once_cell = "1.12" thiserror = "1.0" [dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" [dev-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["bindgen-tests"] [build-dependencies.uniffi] -version = "0.27" +version = "0.25" path = "../../uniffi" features = ["build"] diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py index 7b676c83de23..017e999fb287 100644 --- a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py +++ b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.py @@ -2,7 +2,7 @@ from todolist import * todo = TodoList() -entry = TodoEntry(text="Write bindings for strings in records") +entry = TodoEntry("Write bindings for strings in records") todo.add_item("Write python bindings") @@ -20,7 +20,7 @@ assert(todo.get_last_entry().text == "Write bindings for strings in records") todo.add_item("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") assert(todo.get_last() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") -entry2 = TodoEntry(text="Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") +entry2 = TodoEntry("Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") todo.add_entry(entry2) assert(todo.get_last_entry().text == "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") diff --git a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb index fc1a823f52a5..d9e04f92e7b7 100644 --- a/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb +++ b/third_party/rust/uniffi-example-todolist/tests/bindings/test_todolist.rb @@ -7,7 +7,7 @@ include Test::Unit::Assertions include Todolist todo = TodoList.new -entry = TodoEntry.new(text: 'Write bindings for strings in records') +entry = TodoEntry.new 'Write bindings for strings in records' todo.add_item('Write ruby bindings') @@ -25,7 +25,7 @@ assert_equal todo.get_last_entry.text, 'Write bindings for strings in records' todo.add_item("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣") assert_equal todo.get_last, "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣" -entry2 = TodoEntry.new(text: "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") +entry2 = TodoEntry.new("Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣") todo.add_entry(entry2) assert_equal todo.get_last_entry.text, "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣" @@ -44,4 +44,4 @@ todo.add_item "Test liveness after being demoted from default" assert todo.get_last == "Test liveness after being demoted from default" todo2.add_item "Test shared state through local vs default reference" -assert Todolist.get_default_list.get_last == "Test shared state through local vs default reference" +assert Todolist.get_default_list.get_last == "Test shared state through local vs default reference" \ No newline at end of file diff --git a/third_party/rust/uniffi/.cargo-checksum.json b/third_party/rust/uniffi/.cargo-checksum.json dissimilarity index 100% index 98c4aca54e98..74d539b50574 100644 --- a/third_party/rust/uniffi/.cargo-checksum.json +++ b/third_party/rust/uniffi/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"eb974d356d4da93a076434ff428c448f70e036a724bd9a0a7eae6b9ddff2346e","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","release.toml":"1aa1b131d4cc93b5eba8758a4401c70bc0d7fe5861e2ec147e9259fe7c0da472","src/cli.rs":"5c0b9bb93665f2f49f7e90335e65206887e26e96f2a533eb1203be27c9380c84","src/lib.rs":"422503d7cbac1360852287b1810c99663669625b9abf080a5fec22058bb73d8c","tests/ui/proc_macro_arc.rs":"fedc429603753e8ef953642a7295323ccb3f76fd3ae1ab181ad90c5eb88212bb","tests/ui/proc_macro_arc.stderr":"a24af227b907328c9cac6317ec9f43dbc45d7f7c77c603e5d72db7fa050e8b01","tests/ui/version_mismatch.rs":"16ea359e5853517ee0d0704c015ae8c825533109fbefd715130d0f4a51f15898","tests/ui/version_mismatch.stderr":"21dcb836253312ba8e3a0502cce6ff279818aaaadcea9628a41b196e0c8c94b6"},"package":"a5566fae48a5cb017005bf9cd622af5236b2a203a13fb548afde3506d3c68277"} \ No newline at end of file +{"files":{"Cargo.toml":"5a5cf41b9eb4aac8e312fc9584c0d47585a5a20b13bc7cfb14c9b8813ea596e6","release.toml":"1aa1b131d4cc93b5eba8758a4401c70bc0d7fe5861e2ec147e9259fe7c0da472","src/cli.rs":"0b4791c263d6cf54e4e63dff9a8ead59838d5e7b45fbf5b7f77ab16f602bdb0d","src/lib.rs":"6bc2c11f466fbcd128827a57b5f93a77f716262200f4e5ad2ed8dd75845320fc","tests/ui/proc_macro_arc.rs":"fedc429603753e8ef953642a7295323ccb3f76fd3ae1ab181ad90c5eb88212bb","tests/ui/proc_macro_arc.stderr":"a24af227b907328c9cac6317ec9f43dbc45d7f7c77c603e5d72db7fa050e8b01","tests/ui/version_mismatch.rs":"16ea359e5853517ee0d0704c015ae8c825533109fbefd715130d0f4a51f15898","tests/ui/version_mismatch.stderr":"21dcb836253312ba8e3a0502cce6ff279818aaaadcea9628a41b196e0c8c94b6"},"package":"21345172d31092fd48c47fd56c53d4ae9e41c4b1f559fb8c38c1ab1685fd919f"} \ No newline at end of file diff --git a/third_party/rust/uniffi/Cargo.toml b/third_party/rust/uniffi/Cargo.toml index 374e3655028b..475c8ab9be7e 100644 --- a/third_party/rust/uniffi/Cargo.toml +++ b/third_party/rust/uniffi/Cargo.toml @@ -12,12 +12,11 @@ [package] edition = "2021" name = "uniffi" -version = "0.27.1" +version = "0.25.3" authors = ["Firefox Sync Team "] description = "a multi-language bindings generator for rust" homepage = "https://mozilla.github.io/uniffi-rs" documentation = "https://mozilla.github.io/uniffi-rs" -readme = "README.md" keywords = [ "ffi", "bindgen", @@ -42,18 +41,18 @@ features = [ optional = true [dependencies.uniffi_bindgen] -version = "=0.27.1" +version = "=0.25.3" optional = true [dependencies.uniffi_build] -version = "=0.27.1" +version = "=0.25.3" optional = true [dependencies.uniffi_core] -version = "=0.27.1" +version = "=0.25.3" [dependencies.uniffi_macros] -version = "=0.27.1" +version = "=0.25.3" [dev-dependencies.trybuild] version = "1" diff --git a/third_party/rust/uniffi/README.md b/third_party/rust/uniffi/README.md deleted file mode 100644 index 64ac3486a3bf..000000000000 --- a/third_party/rust/uniffi/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# UniFFI - a multi-language bindings generator for Rust - -UniFFI is a toolkit for building cross-platform software components in Rust. - -For the impatient, see [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/) -or [**the UniFFI examples**](https://github.com/mozilla/uniffi-rs/tree/main/examples#example-uniffi-components). - -By writing your core business logic in Rust and describing its interface in an "object model", -you can use UniFFI to help you: - -* Compile your Rust code into a shared library for use on different target platforms. -* Generate bindings to load and use the library from different target languages. - -You can describe your object model in an [interface definition file](https://mozilla.github.io/uniffi-rs/udl_file_spec.html) -or [by using proc-macros](https://mozilla.github.io/uniffi-rs/proc_macro/index.html). - -UniFFI is currently used extensively by Mozilla in Firefox mobile and desktop browsers; -written once in Rust, auto-generated bindings allow that functionality to be called -from both Kotlin (for Android apps) and Swift (for iOS apps). -It also has a growing community of users shipping various cool things to many users. - -UniFFI comes with support for **Kotlin**, **Swift**, **Python** and **Ruby** with 3rd party bindings available for **C#** and **Golang**. -Additional foreign language bindings can be developed externally and we welcome contributions to list them here. -See [Third-party foreign language bindings](#third-party-foreign-language-bindings). - -## User Guide - -You can read more about using the tool in [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/). - -We consider it ready for production use, but UniFFI is a long way from a 1.0 release with lots of internal work still going on. -We try hard to avoid breaking simple consumers, but more advanced things might break as you upgrade over time. - -### Etymology and Pronunciation - -ˈjuːnɪfaɪ. Pronounced to rhyme with "unify". - -A portmanteau word that also puns with "unify", to signify the joining of one codebase accessed from many languages. - -uni - [Latin ūni-, from ūnus, one] -FFI - [Abbreviation, Foreign Function Interface] - -## Alternative tools - -Other tools we know of which try and solve a similarly shaped problem are: - -* [Diplomat](https://github.com/rust-diplomat/diplomat/) - see our [writeup of - the different approach taken by that tool](docs/diplomat-and-macros.md) -* [Interoptopus](https://github.com/ralfbiedert/interoptopus/) - -(Please open a PR if you think other tools should be listed!) - -## Third-party foreign language bindings - -* [Kotlin Multiplatform support](https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings). The repository contains Kotlin Multiplatform bindings generation for UniFFI, letting you target both JVM and Native. -* [Go bindings](https://github.com/NordSecurity/uniffi-bindgen-go) -* [C# bindings](https://github.com/NordSecurity/uniffi-bindgen-cs) -* [Dart bindings](https://github.com/NiallBunting/uniffi-rs-dart) - -### External resources - -There are a few third-party resources that make it easier to work with UniFFI: - -* [Plugin support for `.udl` files](https://github.com/Lonami/uniffi-dl) for the IDEA platform ([*uniffi-dl* in the JetBrains marketplace](https://plugins.jetbrains.com/plugin/20527-uniffi-dl)). It provides syntax highlighting, code folding, code completion, reference resolution and navigation (among others features) for the [UniFFI Definition Language (UDL)](https://mozilla.github.io/uniffi-rs/). -* [cargo swift](https://github.com/antoniusnaumann/cargo-swift), a cargo plugin to build a Swift Package from Rust code. It provides an init command for setting up a UniFFI crate and a package command for building a Swift package from Rust code - without the need for additional configuration or build scripts. -* [Cargo NDK Gradle Plugin](https://github.com/willir/cargo-ndk-android-gradle) allows you to build Rust code using [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk), which generally makes Android library builds less painful. -* [`uniffi-starter`](https://github.com/ianthetechie/uniffi-starter) is a minimal project demonstrates a wide range of UniFFI in a complete project in a compact manner. It includes a full Android library build process, an XCFramework generation script, and example Swift package structure. - -(Please open a PR if you think other resources should be listed!) - -## Contributing - -If this tool sounds interesting to you, please help us develop it! You can: - -* View the [contributor guidelines](./docs/contributing.md). -* File or work on [issues](https://github.com/mozilla/uniffi-rs/issues) here in GitHub. -* Join discussions in the [#uniffi:mozilla.org](https://matrix.to/#/#uniffi:mozilla.org) - room on Matrix. - -## Code of Conduct - -This project is governed by Mozilla's [Community Participation Guidelines](./CODE_OF_CONDUCT.md). diff --git a/third_party/rust/uniffi/src/cli.rs b/third_party/rust/uniffi/src/cli.rs index 77d7f219a920..b2d3adc2aee6 100644 --- a/third_party/rust/uniffi/src/cli.rs +++ b/third_party/rust/uniffi/src/cli.rs @@ -5,7 +5,6 @@ use camino::Utf8PathBuf; use clap::{Parser, Subcommand}; use uniffi_bindgen::bindings::TargetLanguage; -use uniffi_bindgen::BindingGeneratorDefault; // Structs to help our cmdline parsing. Note that docstrings below form part // of the "help" output. @@ -36,7 +35,7 @@ enum Commands { #[clap(long, short)] no_format: bool, - /// Path to optional uniffi config file. This config is merged with the `uniffi.toml` config present in each crate, with its values taking precedence. + /// Path to the optional uniffi config file. If not provided, uniffi-bindgen will try to guess it from the UDL's file location. #[clap(long, short)] config: Option, @@ -96,29 +95,21 @@ pub fn run_main() -> anyhow::Result<()> { if lib_file.is_some() { panic!("--lib-file is not compatible with --library.") } + if config.is_some() { + panic!("--config is not compatible with --library. The config file(s) will be found automatically.") + } let out_dir = out_dir.expect("--out-dir is required when using --library"); if language.is_empty() { panic!("please specify at least one language with --language") } uniffi_bindgen::library_mode::generate_bindings( - &source, - crate_name, - &BindingGeneratorDefault { - target_languages: language, - try_format_code: !no_format, - }, - config.as_deref(), - &out_dir, - !no_format, + &source, crate_name, &language, &out_dir, !no_format, )?; } else { uniffi_bindgen::generate_bindings( &source, config.as_deref(), - BindingGeneratorDefault { - target_languages: language, - try_format_code: !no_format, - }, + language, out_dir.as_deref(), lib_file.as_deref(), crate_name.as_deref(), diff --git a/third_party/rust/uniffi/src/lib.rs b/third_party/rust/uniffi/src/lib.rs index 319b3c783627..0625bd9c66f5 100644 --- a/third_party/rust/uniffi/src/lib.rs +++ b/third_party/rust/uniffi/src/lib.rs @@ -17,11 +17,8 @@ pub use uniffi_bindgen::bindings::ruby::run_test as ruby_run_test; pub use uniffi_bindgen::bindings::swift::run_test as swift_run_test; #[cfg(feature = "bindgen")] pub use uniffi_bindgen::{ - bindings::kotlin::gen_kotlin::KotlinBindingGenerator, - bindings::python::gen_python::PythonBindingGenerator, - bindings::ruby::gen_ruby::RubyBindingGenerator, - bindings::swift::gen_swift::SwiftBindingGenerator, bindings::TargetLanguage, generate_bindings, - generate_component_scaffolding, generate_component_scaffolding_for_crate, print_repr, + bindings::TargetLanguage, generate_bindings, generate_component_scaffolding, + generate_component_scaffolding_for_crate, print_repr, }; #[cfg(feature = "build")] pub use uniffi_build::{generate_scaffolding, generate_scaffolding_for_crate}; diff --git a/third_party/rust/uniffi_bindgen/.cargo-checksum.json b/third_party/rust/uniffi_bindgen/.cargo-checksum.json dissimilarity index 98% index 40b0b6e3ccdf..880d79a96fde 100644 --- a/third_party/rust/uniffi_bindgen/.cargo-checksum.json +++ b/third_party/rust/uniffi_bindgen/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"037dacd80bb367cfc530c5ca19fbfac091f385cf88ad5bd33c2009fde6d06e3e","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","askama.toml":"1a245b7803adca782837e125c49100147d2de0d5a1c949ff95e91af1701f6058","src/backend/config.rs":"4861dbf251dbb10beb1ed7e3eea7d79499a0de1cd9ce9ee8381a0e729c097dea","src/backend/filters.rs":"8a818952896f9c5f438d6705bb28f56e77fbfce6d9757a2d74e1b3a925ed36e1","src/backend/mod.rs":"2ee9d974cd259f7fb156028b4f4f7601691e94fb5692a6daf0d362df3ecf79a8","src/backend/types.rs":"598df3a861f5d53b2c710848943f6049dd43cb4f37aa81f2c08fd36fc5b2f5d5","src/bindings/kotlin/gen_kotlin/callback_interface.rs":"741100c2b4b484583d34408b276394078a24918c47101fbaa6233df9c4da32f2","src/bindings/kotlin/gen_kotlin/compounds.rs":"b40d1ab8c70d7da458ff45d2ce58efb6cc3b24bf560c093cbec7d0854d461dc4","src/bindings/kotlin/gen_kotlin/custom.rs":"7e619f7320796ecd8c4ced82904b4bd3c6a0043b55d5829274ab3040cdf9cd7f","src/bindings/kotlin/gen_kotlin/enum_.rs":"6559bb00d8e359126b016e549263c0c9bc1dfc5654ed662c0c2912b47931b1e4","src/bindings/kotlin/gen_kotlin/external.rs":"38f42be67105b9a2ca5ecefec959e6659af728bedb9d107a51c595fe6ff5d332","src/bindings/kotlin/gen_kotlin/miscellany.rs":"6541987e627c4ff27a17ebe919b2b5cd97cb66ff41187ed636396b4e35ea2414","src/bindings/kotlin/gen_kotlin/mod.rs":"34328d11c59a67159620a21bc660fae149bbf452a817d6c9d3f7657cc5b79134","src/bindings/kotlin/gen_kotlin/object.rs":"1cb8d1f5eaf06ceaadb6d2cedca482fdd1502c24500ba270d8fcac48ef2f1231","src/bindings/kotlin/gen_kotlin/primitives.rs":"249896ec7d18f0f8d1d5dc8dc66ea6f3d0cc7b13344ab6892fb985f339d99b9f","src/bindings/kotlin/gen_kotlin/record.rs":"96fd1a180095a062b4a9b71d4f603b232f0133f46355a3e427c4064701d900f2","src/bindings/kotlin/gen_kotlin/variant.rs":"d111d6888745195fc2c24bdddc57359e771616102a8d182c5c8ad268b0a13460","src/bindings/kotlin/mod.rs":"ef88eb9b5b7d6f920c62a525ea4d4bf2a3b1a9154afaa012cdb2feea597fbf23","src/bindings/kotlin/templates/Async.kt":"2130ef176ffabe85cc737059203f2bda38df1f22f2398aa338c9d3099e6d46e2","src/bindings/kotlin/templates/BooleanHelper.kt":"50d8a5109e2d2676f25a02772079efbaac61776a76e3e84eebd1fb13294842de","src/bindings/kotlin/templates/ByteArrayHelper.kt":"dc4aafffacb1fa8f3b4e15f714c13b8d715eec178c63bdba6260baf612dd80d8","src/bindings/kotlin/templates/CallbackInterfaceImpl.kt":"be4d5a5d3ed4f7b1d4c9822905c5732bdb8593c3dbf8d4aabab62291d7ccec99","src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt":"76689c1bfa8aa7dc6e2c9e77c42212b9f317763fb35cd7704ca470675dd2648d","src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt":"b497250899bfd0c79bd01d77f23454b12b108fa269055d6f3699be74fb93d015","src/bindings/kotlin/templates/CustomTypeTemplate.kt":"d42eba4334c39749037d14ef9e2219a2e515479c18905df3f49534424317c848","src/bindings/kotlin/templates/DurationHelper.kt":"dfb45fe1b47bc04dd8c70cb98531c40606eca554791132ee6bed2846f8ee099c","src/bindings/kotlin/templates/EnumTemplate.kt":"7cefbb1e29d4e89420f6a95275bbab891984a56978cf4852a1e52bcc82afd9e8","src/bindings/kotlin/templates/ErrorTemplate.kt":"8f41de90753a42cfe33ba837997baa2954208b987e70cec13ecb4124faf25aa6","src/bindings/kotlin/templates/ExternalTypeTemplate.kt":"b1df8566d000431bfc3820a2e455426e810cba6d8683e77ab78ab0bb7d003720","src/bindings/kotlin/templates/FfiConverterTemplate.kt":"bc0bdbc99ee2459f50c84abf6c1bb236a6179eaf519f1c5f5b3f72d8184dc662","src/bindings/kotlin/templates/Float32Helper.kt":"789246343d34594fc39072c1a5393b848cecadb353659fc6e9080fc7e760fc21","src/bindings/kotlin/templates/Float64Helper.kt":"b87eac72da313b1d559b1738bba1c771f43bb7566fdbb3a34546dd56beeb5832","src/bindings/kotlin/templates/HandleMap.kt":"feb456ea4dfb2ad07331d49d606faf396737817c6f6712a2d9a9d843daebdc1e","src/bindings/kotlin/templates/Helpers.kt":"e7657732f44e8092d492ef291e3ce11aa803531d82be99645b8513c00dca99ac","src/bindings/kotlin/templates/Int16Helper.kt":"54bb1aefbcae1c3c10e0cdc6a9d45e070e3ca57c9ffa53b2d65e5c59808c9743","src/bindings/kotlin/templates/Int32Helper.kt":"49b3e5274d5c7853d227ec986d0a0c71621a448391b2c9aaf4351b86f310dadf","src/bindings/kotlin/templates/Int64Helper.kt":"264fd99a4109f0b2c40b806fc1a0181f27331346a02d94e398f1e34110e3414b","src/bindings/kotlin/templates/Int8Helper.kt":"a50c315d8474a212914f10f43ca7e75061bb73067e0de686b182891c6c7f1bc3","src/bindings/kotlin/templates/Interface.kt":"c66912069c3f61848bbee3d1886abbfa74895f759853f6b4a3c62cef5976766c","src/bindings/kotlin/templates/MapTemplate.kt":"f7e0360d3be74e543573bd56925bf25c6c22e6203aecc1cf519464704eeeb0ee","src/bindings/kotlin/templates/NamespaceLibraryTemplate.kt":"db4c30cfcb709c5413892cf3cf69391ba36c6160543274e8d1f2bedf9001d058","src/bindings/kotlin/templates/ObjectCleanerHelper.kt":"9ebcfcb3fe7788e93cf8cba30fd7470b363719e9ed25cdde43c95aebe1b90c2a","src/bindings/kotlin/templates/ObjectCleanerHelperAndroid.kt":"049e1e32a23b7923393e3dcabce49532737d44e9dbb331f62984ada67bde3125","src/bindings/kotlin/templates/ObjectCleanerHelperJvm.kt":"b6287f72afdb0ab9af5e56136c28e6a4f5e18a50305bce8923ee061b9406cfc3","src/bindings/kotlin/templates/ObjectTemplate.kt":"6a776feb36b0379c43e0013a26ba85cdef385aa1e59b4c2efa7a794140aa99bb","src/bindings/kotlin/templates/OptionalTemplate.kt":"918f2029e60710f4b048a77830b12b388c917af1a488c9f05f38323c58ee0f9e","src/bindings/kotlin/templates/README.md":"83587ff54a31fa47d2c0849cb5db52d6f079551e1cfb73c76c6dd02a7b164ad9","src/bindings/kotlin/templates/RecordTemplate.kt":"677bb63ae4fae9117e9c77928370a8911ab959c6b884c6af2ba4efc686c52721","src/bindings/kotlin/templates/RustBufferTemplate.kt":"b3b78b2c41cbfff6262d758f9ebe064e76d20841ec4db7705142449f7ffc75a9","src/bindings/kotlin/templates/SequenceTemplate.kt":"c1aa28ca87528c97c62656f850205023c2eb8d218264ef7b1e70207ab4f1b9b6","src/bindings/kotlin/templates/StringHelper.kt":"4e942e36af05dc823d5f28ab336c55ff86bf0f95bbb748399bcaa8ad291c7032","src/bindings/kotlin/templates/TimestampHelper.kt":"70137e78de18796996889e8d648f1e90830aa652a93a0b4639ff9f7ccb967a25","src/bindings/kotlin/templates/TopLevelFunctionTemplate.kt":"68c714cc8c7fa244166c5902a59c90317cdfc402193624cade405e3454f9bf67","src/bindings/kotlin/templates/Types.kt":"c725f7e57eda5b2d52c3c92b24f93d9321591e72c89d16973163b3b8d713b85b","src/bindings/kotlin/templates/UInt16Helper.kt":"ee96270f426933cfcd914894d4c7895544f7e3d4a7c24be78afc2896b46cbcbe","src/bindings/kotlin/templates/UInt32Helper.kt":"b2d7543098277e7b92502a0a6693dc25dd42e360f776b19987a48dd7fc6db7fd","src/bindings/kotlin/templates/UInt64Helper.kt":"fc855eb78a4b50d76fc53509dae8218c48a221db5bf73cf5368d755fb9aae478","src/bindings/kotlin/templates/UInt8Helper.kt":"af22d9e6f99fe9d8d7d5175cb03f7a9f62628c9dd939dbbfb5a4085359e52e0e","src/bindings/kotlin/templates/macros.kt":"0a221962503f6977b129eb3c1e3772e3e9d51cbab6d813c55b0387c24d784184","src/bindings/kotlin/templates/wrapper.kt":"a02028a86c620679602f26714c7feb4a306867cda1cba8240ca6e83d99cebd91","src/bindings/kotlin/test.rs":"28bf88a9e9aa9510adbe78005a2027a62818433f49426172046dc83a3ad41911","src/bindings/mod.rs":"949f323d6eb5c018497103dbb9dcffb8f395eb5960694b551a24b4887e853afb","src/bindings/python/gen_python/callback_interface.rs":"5df3e091d3c88ef7645e570f693942161a9b9c6307419c15a2534fbc5da974af","src/bindings/python/gen_python/compounds.rs":"4a83b02e11ae969ab360ba61df44d91dc790f372b5960b350b0b019a57d19de4","src/bindings/python/gen_python/custom.rs":"81501641648eb638f5a338c01a71db0d0e96601c3dda83acdb2d49072b387d42","src/bindings/python/gen_python/enum_.rs":"7c3f8f6a97c1491175c8b93b8f9ab13748e2f8084bb717836b6935d024805439","src/bindings/python/gen_python/error.rs":"161bd2e041e3a63a91899de173eec8450cc10e1e9552d064969aa72a02fdfd5e","src/bindings/python/gen_python/external.rs":"d7101124c22dd7837e227a7f1b683c57b92229a2cd5b25b06740f2fe3d76bed5","src/bindings/python/gen_python/miscellany.rs":"d6f6305dd0af85b7ba87b70cbe6ecba00c83d5082c5bdcaf25962fff853973ea","src/bindings/python/gen_python/mod.rs":"b8aac9a146551cd660f1cd310f8ef02e3bd4a11540a087551bbb7c7706b99e16","src/bindings/python/gen_python/object.rs":"a4d4c20a0a52687feff2b9a547a13aa9bda09b3af9ec26508646658a88eec8b3","src/bindings/python/gen_python/primitives.rs":"b830c68e20d8539b8ac5566f1ca0dd262c1b14712a747f79e70004cd8f409ba1","src/bindings/python/gen_python/record.rs":"f8e12ce43d7e0f37f05420a849e7867b7251f9790933609a4cb99050fd063089","src/bindings/python/mod.rs":"eac32ce383460d58d3ccf1d406173465fc8a1db8a24408df67620b7d14dcd0cd","src/bindings/python/templates/Async.py":"f1cf32d8e28b5e2fcbad6ccd00d03fd49f4b54eac47adcfe23cbf786d523eee7","src/bindings/python/templates/BooleanHelper.py":"cf7bcd414197258b0cfa54c6ad2aeb81a1a6a4a45af5b6aaf6f8e484bc5af59d","src/bindings/python/templates/BytesHelper.py":"8c39cf1760678316cf2b3903632f2bacae4f8aaa961b37eeb03e06e9f07241d1","src/bindings/python/templates/CallbackInterfaceImpl.py":"7dbb049ffebc3565ffb4605d53843c69f782f3e86472e060e3194be4986d328b","src/bindings/python/templates/CallbackInterfaceRuntime.py":"54dbda8a6ffe284ef2045da290a69d37974fed672eb57309c9fc7ac665969397","src/bindings/python/templates/CallbackInterfaceTemplate.py":"ef235bd7927592eb19a2db422352a435b7466595ef31e4822a16c3caa24cdda6","src/bindings/python/templates/CustomType.py":"4647a60dbe63ead2b23d07cf3a3a4a190a219d81357532364fd4afdf990d6e1b","src/bindings/python/templates/DurationHelper.py":"eb9278b546f79b71525ae61a5b30bfe4a1260fd2268c87c600d157bf9b0e2a44","src/bindings/python/templates/EnumTemplate.py":"49903d969b8b160d8f1a0747c803d5f54a6f000a6781493eacad1f6ca7811d7a","src/bindings/python/templates/ErrorTemplate.py":"d7af297596e5ef894e3fdaeb92bd6446843c987f8283c77973bd10fce537c9c1","src/bindings/python/templates/ExternalTemplate.py":"0cd36fc89f0a587dadfe0cb89c4d45a641822ba07cb9410299bdcd73ad3edb79","src/bindings/python/templates/Float32Helper.py":"4aa522163f121fcb84d2f024774d8dd9321c31f09b9a95da3a3131b6d2756971","src/bindings/python/templates/Float64Helper.py":"e7fa247fd9c3907b818f0d1ba28c2cee897e75fdd07fdacad1b8a2b5c26ba418","src/bindings/python/templates/HandleMap.py":"9dbfdcb4ddde5927fd9b9fb26b5194bc16b1d2280c2259895fd0ea443af4afd6","src/bindings/python/templates/Helpers.py":"09ddd46d6fcc6ee7e9b1c123b0830426c967f94e22ab18b3ee248b873f7d5ebc","src/bindings/python/templates/Int16Helper.py":"613345b35e63e7284caf97de9630747ec9cdadc8dd3f8451d2e878cb762958f5","src/bindings/python/templates/Int32Helper.py":"758b093b66dc0a8d3f0b13b9388d21f47de31b5e948689041c4d43ef98cf2c4f","src/bindings/python/templates/Int64Helper.py":"c7e76441ee14e78e856f8819f73243bc04b33ec16083ae7390e0ec27141855f2","src/bindings/python/templates/Int8Helper.py":"d963a76b218a32ea2b3bb26f265dbbc47e859b7d1bc939b43fd9b93c51a62292","src/bindings/python/templates/MapTemplate.py":"9dc81ebced353d0137ef6fe3187e170e3e72d32a3b5520dbbcc1f95354ebf62d","src/bindings/python/templates/NamespaceLibraryTemplate.py":"e480a80a27ed5e54a3ff9c72d3d6ab13343764da6c413d813c4bd72429139193","src/bindings/python/templates/ObjectTemplate.py":"976aa726baf36b53d1c319b262c34b8b2de2e414cb8d3c645ed3bf006833b9e8","src/bindings/python/templates/OptionalTemplate.py":"2629f3b46ff394df620bbff1699935e6844d9aa017e74ac43c0b38acd05f8d42","src/bindings/python/templates/Protocol.py":"8446fe51d7c9d16d7086694cee8016c6f571dc5c930fd18848fadcf109aa0566","src/bindings/python/templates/RecordTemplate.py":"c99d10cc061af339349bb0c7e8b67223fdcd9064362badc137a2ad0df17c57c0","src/bindings/python/templates/RustBufferHelper.py":"a48e5ed1dcde19993ae50bec9b881afa3bc6dd5f7d8257fd60214f2100224929","src/bindings/python/templates/RustBufferTemplate.py":"017f31fd5075306f5c8c2bd0e3a21ea965c694c0daf2523187ab076fc786e9ca","src/bindings/python/templates/SequenceTemplate.py":"1b262e5f546a1923de6968e0233cc621a5fae16062e9e6ac874c9b62d8f145df","src/bindings/python/templates/StringHelper.py":"b303b7fcbbc0981a28c6a7d0cc5bd90f8e9c8b8d572792e217a324b2bdb95dbd","src/bindings/python/templates/TimestampHelper.py":"b3da14de54822f44ada4459355c842550b944b3cd2a85a4eac0f59e82d646877","src/bindings/python/templates/TopLevelFunctionTemplate.py":"1d9da1b6ca2175b30f3277a46a1749590490e82bee6b990ff35efb04e5f102ef","src/bindings/python/templates/Types.py":"3653e2cf773493c6ddfd13ef298b0c7cb33fabc1dba495fca64b9287aae03042","src/bindings/python/templates/UInt16Helper.py":"8ffe4b69a5d4a2b3c5677ff1d8954efc67ab67713ffe297380e930e0379d493d","src/bindings/python/templates/UInt32Helper.py":"83f9603aceae05f2134c7183313ab0a1a8f64cabd8070ae19557494fe41dd6d2","src/bindings/python/templates/UInt64Helper.py":"97269025377a256e821e57991b07e17af05f4d1c4228e01fe5f243d784cb509d","src/bindings/python/templates/UInt8Helper.py":"4896723ed0ab8f5aef4a58d599e0a0dbd63d373f5740821c21b4b429b6a7afda","src/bindings/python/templates/macros.py":"d766feb4dedd2d0e4cd2052da7a69c0b074b97f880b857ee457faa43975230ed","src/bindings/python/templates/wrapper.py":"ab05168e3d01d1a26e9589cd9855d7776c46c59d699f1402a29dfae6eb9ebfbc","src/bindings/python/test.rs":"69d3ee230820f38d743438c8212e1bfc4e92f948d9e73548a38c093e164b2759","src/bindings/ruby/gen_ruby/mod.rs":"861be105f9001d4ad8f7b8ac4a303a95459ec7de7a0c2fdac14a083c43d5a07c","src/bindings/ruby/gen_ruby/tests.rs":"7dcb86b08e643c43503f4cac6396833497f6988b004321c0067700ee29ffbf32","src/bindings/ruby/mod.rs":"0fdfab5306dc5c05fbcbfb273340d96ad70c5caf5074834ad6851af1a9a56734","src/bindings/ruby/templates/EnumTemplate.rb":"5480edb347f5829e478d19474691babd72f37616ed846d519b5a61cb1d6cf047","src/bindings/ruby/templates/ErrorTemplate.rb":"301c177e639f0a27f19d4935c5317e672aadecbee2f9bfa778df982320f5148d","src/bindings/ruby/templates/Helpers.rb":"ce7ed4be97dad507b991c69c28dc7bb6427e5e79a4b2fba9dad9dccabc3e090c","src/bindings/ruby/templates/NamespaceLibraryTemplate.rb":"9a24c427b9eba99d9e13181a5559a385b5d1d16beae2b72a402f2645b22a9048","src/bindings/ruby/templates/ObjectTemplate.rb":"a1c0cc38865195d61df3540284f4756f1b6406b205d74e3855e7089d763b2791","src/bindings/ruby/templates/RecordTemplate.rb":"343a4b159cf298045747fb48f17552e3bf2c9775fa5b4fa40b424976dc67e33a","src/bindings/ruby/templates/RustBufferBuilder.rb":"a36d9183f3e66cbbb1c3e584b78ab86e01bd6b89a4a5ef9614c5df24dc383acc","src/bindings/ruby/templates/RustBufferStream.rb":"ab4fc736906e320fca56dca280daf40138ba443d957c42fbf5cfbf1c6acf463a","src/bindings/ruby/templates/RustBufferTemplate.rb":"de577fbae811f72e260270656f2c12ad7a4d157c78f97898d0cd4e309d92ad6a","src/bindings/ruby/templates/TopLevelFunctionTemplate.rb":"26c9c2d53853792270795bd822e41968e995375478d246f808f9935af77a7d6a","src/bindings/ruby/templates/macros.rb":"dc60ed79844b04fe828a24aef3550a6b6c30f7c0b66f03608d7c56725287ceed","src/bindings/ruby/templates/wrapper.rb":"f82b41543546f8e5804cd0e1785f4735d9dd95383566d0e5ba1cd4d9e8c0578d","src/bindings/ruby/test.rs":"027d62085498b20977f025117e1fb7c30923a189961d679823f16ca62a575d0d","src/bindings/swift/gen_swift/callback_interface.rs":"1a2b56d16db841574be0762d66b57fbaef0519273d45c47ca687bf656546f201","src/bindings/swift/gen_swift/compounds.rs":"d62206bdab8a2a65b19342933efad54c171f0f8c217b82ee8b41617043662fe5","src/bindings/swift/gen_swift/custom.rs":"bddb601b4ea8810ecbad01271d5ec0b3958999b09bc9382c83637dfd43451734","src/bindings/swift/gen_swift/enum_.rs":"87be67ec3394616368d9ef8e99b7f234c053b3bee9a7f9e6f2dff37f147c8837","src/bindings/swift/gen_swift/external.rs":"a1d34b688679a74b0ddcfcb1147a7064b53883d9df9c0670f950078516492ee7","src/bindings/swift/gen_swift/miscellany.rs":"7fc2444596d76545ad82ee6c4bed64a29dd4a0438d50bfaafe511f41f6a0e409","src/bindings/swift/gen_swift/mod.rs":"e6c12506217d0a5479e946998a24ee984e4ea4c4f19334cbd014f53504300181","src/bindings/swift/gen_swift/object.rs":"45a6d6bb053f3ef397ab8c6feba8d0e126a8d14cd87597d25015f97c6ffc3417","src/bindings/swift/gen_swift/primitives.rs":"26a29ea764988d9e021bbac6505ef45e49ae42426522d6e3822e949b6f0b589c","src/bindings/swift/gen_swift/record.rs":"5ad98ab04a5d8178daf0956db819c87d26aae7bf968184e88d512e34c02feb90","src/bindings/swift/mod.rs":"26ba270cb7913661f3cee703038d1ea4a70bff64c3b31351d6bc77e67cdee20d","src/bindings/swift/templates/Async.swift":"1645ac8dbea8575dec05acf0aeb18e210f76231c36ea0178b183e02a3ff6e18f","src/bindings/swift/templates/BooleanHelper.swift":"f02e391bed44ca0e03c66c4e6a1545caaae490fc72c4cf5935e66220082a8c30","src/bindings/swift/templates/BridgingHeaderTemplate.h":"4e1e91859c4fc6f40db32648645f046fb7e71841f44ae84737ea85bdecff7fa3","src/bindings/swift/templates/CallbackInterfaceImpl.swift":"514a0932c445e4040460da2969e4f21595e17b9b960eb23c6d1526e47dd56c51","src/bindings/swift/templates/CallbackInterfaceRuntime.swift":"a5def6b3b41698a42e6ccf5c85d365fe0abc7eff629d9f49d9d396ee90aad3a0","src/bindings/swift/templates/CallbackInterfaceTemplate.swift":"4dcab3e590f897499782aef3c657b9b838b312d8b49a018bf0f1ebde15ada786","src/bindings/swift/templates/CustomType.swift":"71520eb38a4be9035dca9e3e0402f386e7eaa79b28568bbc2f20d3fd53b4544d","src/bindings/swift/templates/DataHelper.swift":"df11547a2df57dcca0ff9cddc691bb5fa07d5ffd3d328d1c3b4443078008b111","src/bindings/swift/templates/DurationHelper.swift":"cbc41aaa58bda6c2313ede36a9f656a01a28f9c72aa1624e0e1c1da7b841ffb6","src/bindings/swift/templates/EnumTemplate.swift":"4b980f8bfe65266d27d561e88c7d79d87f426b35b4b842ef80c5d56841e2f672","src/bindings/swift/templates/ErrorTemplate.swift":"1233d119320a44dbf6099681595dda9bf5dd2a1474af4380b704bff0563c38ef","src/bindings/swift/templates/Float32Helper.swift":"ea32538058c4b3c72b1cd2530ac00d0349fadab5e1bc617d33aae4c87692fc98","src/bindings/swift/templates/Float64Helper.swift":"e27e9424dc6e97b8cacc6ca4c796dd2d16dcfcb877e2f19c45eca03381a41e78","src/bindings/swift/templates/HandleMap.swift":"acd2b06d678e64a573f7b842c7d08b87140ddb5d7146c0bf3401d99999399ec2","src/bindings/swift/templates/Helpers.swift":"491553eb82cdc5c944451a541d4e4655537cccb961f220783459b57b2311ca84","src/bindings/swift/templates/Int16Helper.swift":"204906911813a3931436057c23032f4c4e39e023df90d641d6c6086aefe2f820","src/bindings/swift/templates/Int32Helper.swift":"0997f059c9c4edd3c41aee0bbad4aa2bda6d791a0d623ad8014d5aa6bdae718d","src/bindings/swift/templates/Int64Helper.swift":"bcf8c2deebb3ee9bce87735adc4bd100981989943b69f6a7fb499a9aec4c25d9","src/bindings/swift/templates/Int8Helper.swift":"ad1ec0fa213724933fa4dc4e2e304e13ac4722b774bfffac44793986b997dd33","src/bindings/swift/templates/MapTemplate.swift":"53971ec388417b02519f8deb8d66361ab4693eae77d116f6051cbea4738054ec","src/bindings/swift/templates/ModuleMapTemplate.modulemap":"99ad1e9bf550a21497296f9248ecd4385dd6d0b5892951d24cf990cdbf3eec2c","src/bindings/swift/templates/ObjectTemplate.swift":"37e57815e60900ae48b953fe01e01535d4ab8076f6160fc93c37dd08fdee47a4","src/bindings/swift/templates/OptionalTemplate.swift":"2376487ceadca3975f0e82ddf6ce61af8bbbf5b0592fa9cd977460f148d8c99d","src/bindings/swift/templates/Protocol.swift":"2614b1378cadf14e7617fedd7367c227ac2a774d528acd3a42e44fd0c4f58528","src/bindings/swift/templates/RecordTemplate.swift":"f9f576b72fda9d1e1db34d1765ec6ec8206103a297329720c1c9a1f58ad085b5","src/bindings/swift/templates/RustBufferTemplate.swift":"89ed33846c0cfb220e823a1002238b16f006f3170d8de0dbbf7775d4f8143c31","src/bindings/swift/templates/SequenceTemplate.swift":"8425b279197582a94b4cf363ab0463907a68a624e24045720ef7df2bcacf3383","src/bindings/swift/templates/StringHelper.swift":"968b9b9b7fbe06a2ac2143016edaff3552e201652accb8d613b03645f0d24a90","src/bindings/swift/templates/TimestampHelper.swift":"82eece13aa186c8e3745c8ad2f1290639ca9689573018a2bdc5c75afbae58c26","src/bindings/swift/templates/TopLevelFunctionTemplate.swift":"7aa473a5b12ad7623f61d6c31f6879f269f51d2c4134dd899ce24c7b31ef35f1","src/bindings/swift/templates/Types.swift":"15e255e35e267f2aca49ed5a4fe16ef79520f4261433fd30c5e6c7f637a4d3f6","src/bindings/swift/templates/UInt16Helper.swift":"d6fba577324fc0e9e50329c968df99341de418011be126bd29702f8a94d87c02","src/bindings/swift/templates/UInt32Helper.swift":"5e0cf151a0c40098b3d96815ba3de23e15fe52f3c517577e1b0c7e7a4c12428f","src/bindings/swift/templates/UInt64Helper.swift":"17237b38d09ced8d2a8ff1ad9ca86873a19e417280e0e60f33d7063397ea4b7b","src/bindings/swift/templates/UInt8Helper.swift":"c4cb2ee4a78b54ca8d0013383c6b43e9ecd42776e3dc7d6e40086325d41714e5","src/bindings/swift/templates/macros.swift":"b30ffd93fe2213e13c3b9910bf2404403b4b231d4cd32c81e0f76c3bb4d151b5","src/bindings/swift/templates/wrapper.swift":"e553af470320391d150e6489eac549064689a37e5db6947914ce5609d0128031","src/bindings/swift/test.rs":"f55ba6c05c250093b26ae91404fd9200951462c1cd99e6b2718f7fb4ebcb7fbb","src/interface/callbacks.rs":"4a019376ec8fbaec495a9e3a1d5cb079af65767b6d85bc9f508f92a1e7f5344f","src/interface/enum_.rs":"7baee60e02cc7f751d7a941e877c10a6afaffea626e79897a0e8b17702f13c15","src/interface/ffi.rs":"11b48aaf22fd9cd9eeded30afe950b26cc1c6d8ec6f9385c9e4cd3bdb2881f43","src/interface/function.rs":"be0f9f268e1947381fa235c5a0cf3c1965fd73121172d31f9c130acf539f2ac0","src/interface/mod.rs":"b97b11295b91691e7e6b7b023bba019729ad02f2204bba460c48acf62c5ee363","src/interface/object.rs":"d37d55edc62f52cf7fac4e3b8be1e46557dcbcfa8eb2e5998a91be2c6c062d92","src/interface/record.rs":"d8ddf873c35beaff45ab522bc4cb809c459a7937fd4061dae8c2db0db4c4edb4","src/interface/universe.rs":"76f368ff2b5326c517025a460405d343618bcc9fc9cfb28346313c8f7a335050","src/lib.rs":"2e3adccd5f0a3dacce6e533edfb5640ddee05e4f87ce8144cba859a14af219f6","src/library_mode.rs":"43ee55e4bb8d27dcec8a164961f22de941603d79d4e10c270ba9e7a751d92a1b","src/macro_metadata/ci.rs":"fa87ef42065c821aa89d3fb7938888c035ce6fc03bb3fce575a878c8e49012fb","src/macro_metadata/extract.rs":"7554c7b19b50d40e90bb503320311c2caa3b1e45e4376a9266ce32c0d48afffb","src/macro_metadata/mod.rs":"bcb5e9a015510e9d74c288da928a4bfb8d80926a8ff85227c0eae8cdb2605519","src/scaffolding/mod.rs":"66c3f2d9e81ded234fdd5b34cbb1da334cc271fa6ff3daa41b9acf9ac02f2194","src/scaffolding/templates/CallbackInterfaceTemplate.rs":"11acee064df46f7b5132401ae49c03c77f296bc04065085d6fd5c4ad6b628718","src/scaffolding/templates/Checksums.rs":"ee926e840875c2e48e1d0cc5185c11f7a1ed3bde5264b07540812cb13c1d7481","src/scaffolding/templates/EnumTemplate.rs":"305b8f0e6ec38300f0ae576a1bf1c576d0088d0df8d0b45818ad25f0216a7ac0","src/scaffolding/templates/ErrorTemplate.rs":"e6ec4e1d4c594d9f14a8dfe0a24103a66c0cc91d2129f0e1644775740f85bea1","src/scaffolding/templates/ExternalTypesTemplate.rs":"4c45cefca1774de3f3b650ce3b9a1b1b8fc10c62e0e48e54ac300748c32959f6","src/scaffolding/templates/ObjectTemplate.rs":"80689b74cbb426e6ce8bce77359b122d747b34b48d9a30aef44f93c9aa726fa7","src/scaffolding/templates/RecordTemplate.rs":"644177d86b52bf39c277b4e60a66f594b3fb0454f6b62837f9041297135c09c9","src/scaffolding/templates/ReexportUniFFIScaffolding.rs":"aa8a1ffa98b6033707d965f90b5709474ed6bc79486fb47dacae8417fc056cf8","src/scaffolding/templates/TopLevelFunctionTemplate.rs":"c11a688cafc2e21c3be105533b34c1f73eab55202936f7c8a97191d7e27f26e0","src/scaffolding/templates/UdlMetadata.rs":"d7c50af1de92ef85630b385a910c7b29875502d622eb90da5541a7012b93d9e2","src/scaffolding/templates/macros.rs":"ea6bacd8dd9116ad739bdafe893d70407050f35e4a7ac8dd2c78b8ef34263e8e","src/scaffolding/templates/scaffolding_template.rs":"c8e18306a73ec5b764f665660fc5c91d498b63b6c3f489e524b2bae50f81f231"},"package":"4a77bb514bcd4bf27c9bd404d7c3f2a6a8131b957eba9c22cfeb7751c4278e09"} \ No newline at end of file +{"files":{"Cargo.toml":"5285a403f48ecf7a073cbe1839c7afbd0e14998e8315b1ff8ecefb9e7171fc4e","askama.toml":"1a245b7803adca782837e125c49100147d2de0d5a1c949ff95e91af1701f6058","src/backend/config.rs":"4861dbf251dbb10beb1ed7e3eea7d79499a0de1cd9ce9ee8381a0e729c097dea","src/backend/filters.rs":"2da4eaa9af92e449f2fa20d06fc2ab2f758a9a10d3ad6cb8a94975184d40d2ff","src/backend/mod.rs":"2ee9d974cd259f7fb156028b4f4f7601691e94fb5692a6daf0d362df3ecf79a8","src/backend/types.rs":"598df3a861f5d53b2c710848943f6049dd43cb4f37aa81f2c08fd36fc5b2f5d5","src/bindings/kotlin/gen_kotlin/callback_interface.rs":"a6c7796ca66cbaabeef401b939d3c707bba17a77581da36a3a0b46f87630440e","src/bindings/kotlin/gen_kotlin/compounds.rs":"ebd2111a74032b336e0768facfb756a9422da2f9b413ee929b24c1c4315e6a06","src/bindings/kotlin/gen_kotlin/custom.rs":"7e619f7320796ecd8c4ced82904b4bd3c6a0043b55d5829274ab3040cdf9cd7f","src/bindings/kotlin/gen_kotlin/enum_.rs":"6559bb00d8e359126b016e549263c0c9bc1dfc5654ed662c0c2912b47931b1e4","src/bindings/kotlin/gen_kotlin/executor.rs":"58a192123fd2dd4b625f29d95ae6bf5161c2fef7bf50aa8790c3ae0e7a9430d9","src/bindings/kotlin/gen_kotlin/external.rs":"bcd2a44f2559a124aa287944ab59296239033372c6b4a7a3b625b1d41c441de2","src/bindings/kotlin/gen_kotlin/miscellany.rs":"6541987e627c4ff27a17ebe919b2b5cd97cb66ff41187ed636396b4e35ea2414","src/bindings/kotlin/gen_kotlin/mod.rs":"ccae80314058df0b4988d0965ab62b0dc872e8676592e7b55037cd54011e6854","src/bindings/kotlin/gen_kotlin/object.rs":"539ec05386c1e844bef09d4de8374760daa5ba99b009615c04be9c3927feb4c9","src/bindings/kotlin/gen_kotlin/primitives.rs":"2c3020416384a67855ca5086e485c4db6d7dcc3ce51343217b4a914b318ae350","src/bindings/kotlin/gen_kotlin/record.rs":"96fd1a180095a062b4a9b71d4f603b232f0133f46355a3e427c4064701d900f2","src/bindings/kotlin/gen_kotlin/variant.rs":"d111d6888745195fc2c24bdddc57359e771616102a8d182c5c8ad268b0a13460","src/bindings/kotlin/mod.rs":"ef88eb9b5b7d6f920c62a525ea4d4bf2a3b1a9154afaa012cdb2feea597fbf23","src/bindings/kotlin/templates/Async.kt":"064ce385ac0e68719de625e0172908257714b62da296ff14b2c0153b9966212a","src/bindings/kotlin/templates/BooleanHelper.kt":"28e8a5088c8d58c9bfdbc575af8d8725060521fdd7d092684a8044b24ae567c7","src/bindings/kotlin/templates/ByteArrayHelper.kt":"6fbb424556f631beb7f28c4168c568ad840445496a29d5c8f40a9a591b1661b1","src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt":"29fab10a8f6b699471e793e8d53f5bed74803a8c433ff80ccef5f56cf742c54a","src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt":"3b063ea03959c95327b6082c7edc0db0df83ee8b9e8d643b92ca45cf4fda458a","src/bindings/kotlin/templates/CustomTypeTemplate.kt":"be9bdc716731f3935a4d48728e33bfeb4acd514f3719ddbb273adcd6fb4ab31f","src/bindings/kotlin/templates/DurationHelper.kt":"414a98161538a26f3a9b357353270c1f245ad6ceed99496aca7162cf473a92fd","src/bindings/kotlin/templates/EnumTemplate.kt":"865fb1badd1a128390903ab8d9f42f9208c6db0eac5e53b88207282176cfd67f","src/bindings/kotlin/templates/ErrorTemplate.kt":"394c0093c0c86a0f2a14cd5fa60a70ba9970c65448867b6aca86fc25cfe08a4c","src/bindings/kotlin/templates/ExternalTypeTemplate.kt":"40df49116f9ea227c9a64a4f45bb7c2e99275c62e93f75290808e2c930911fba","src/bindings/kotlin/templates/FfiConverterTemplate.kt":"aa22962aaa9f641d48ccf44cb56d9f8a7736cbfaa01e1a1656662cfe5dd5c1d7","src/bindings/kotlin/templates/Float32Helper.kt":"662d95af3b629d143fb4d47cb7e9aa26ed28a5f3846de0341e28b0f9fb08bc25","src/bindings/kotlin/templates/Float64Helper.kt":"a77d099fa7d91e8702c1700e7949ffb6aaba9c6e8041ff48bab34b8e1fc9a0aa","src/bindings/kotlin/templates/ForeignExecutorTemplate.kt":"09c63a67adb8c6cb807108f02d7695d3425401ea0cc51b582cfd469a322fcce0","src/bindings/kotlin/templates/Helpers.kt":"90a11ec576e82265ba0f95fc330053779aada5976477f0d4a6b38619da1282cf","src/bindings/kotlin/templates/Int16Helper.kt":"7f83c4a48e1f3b2a59a3ca6a2662be8bc9baf3a5a748b31223cb3f51721ef249","src/bindings/kotlin/templates/Int32Helper.kt":"e02e4702175554b09fd2dd6ac3089dcd2c395f08ec60e762159566a9c9889450","src/bindings/kotlin/templates/Int64Helper.kt":"7a6fd6ca486852c89399c699935a9dfa1c32b9356d9a965cfde532581f05d9fa","src/bindings/kotlin/templates/Int8Helper.kt":"0554545494b6b9a76ce94f9c1723f8cf4230a13076feb75d620b1c9ca1ac4668","src/bindings/kotlin/templates/MapTemplate.kt":"07d20d8cf58a4bca950ac22dbec5e3471ac6c18c3cca562e45628de827b03ccf","src/bindings/kotlin/templates/NamespaceLibraryTemplate.kt":"22226bb8dde52f12c77b40bbb8f7ceb7dcef313950b8d42b2f5fe44777158bfc","src/bindings/kotlin/templates/ObjectRuntime.kt":"7f38f54a0c889d7534d23afdace6b87b6ced5c024a36b5450078a06e071caad8","src/bindings/kotlin/templates/ObjectTemplate.kt":"3f3baea52b6923446827ea1ee3f5160edfe81e00c11f61ea1f72dbc6b796a6d8","src/bindings/kotlin/templates/OptionalTemplate.kt":"c916c4545d37087ee01a6b6aef966928691d26be539c388fce608e9e3ff4b0e7","src/bindings/kotlin/templates/RecordTemplate.kt":"8d573856de75b55b985594ac4e4a6f08da931dce6b52420654b5bb080eec414f","src/bindings/kotlin/templates/RustBufferTemplate.kt":"002878ce9ce9924231e55853b86768fc3dec2caef6a28098f01c3edd739ca076","src/bindings/kotlin/templates/SequenceTemplate.kt":"477a0f6714af151ca58cfc7c4f2cf0e878d391dd9db4efe964f19d5ad4f544f0","src/bindings/kotlin/templates/StringHelper.kt":"ec0441da90a394616d0ba3492eca50602161fe42062bc4f60e9a23191e71e009","src/bindings/kotlin/templates/TimestampHelper.kt":"353c2890f06ad6dda238e9aebb4bdff7bb838e17e46abf351ed3ff1fbc4e6580","src/bindings/kotlin/templates/TopLevelFunctionTemplate.kt":"888ef82e2637ab104f0821803666c77212b5d5940414f71e899f8f8968ffe572","src/bindings/kotlin/templates/Types.kt":"4d87ef529f666db532fb5355a339fd50be3edd6225a703564455b81ef4d4a16d","src/bindings/kotlin/templates/UInt16Helper.kt":"e84a1f30a5a899ba2c5db614d3f3c74f25bccf6dd99bf68b8830829332d051e9","src/bindings/kotlin/templates/UInt32Helper.kt":"7cdf08cc580046935f27ba07b53685968608a102e0a6be305111037c63d7ddf8","src/bindings/kotlin/templates/UInt64Helper.kt":"fd7baacbf3ab6202ff83edcc66e5f7beb11a10053ba66d0b49547616cc7cbe1f","src/bindings/kotlin/templates/UInt8Helper.kt":"bbf5a6d66c995aea9fe2fa9840c6bfa78b03520a09469b984f0e1d43191e453a","src/bindings/kotlin/templates/macros.kt":"0f64366a9d7523b3d20d7e9d8b04eb064568772dec529a12f878acf5d2246a41","src/bindings/kotlin/templates/wrapper.kt":"d515ca22d12f13b1b99c5daa411ea35d9a288076e4b7208eaf88170e5da7477c","src/bindings/kotlin/test.rs":"0f752ab0afde20194afca07af94da9d1422300032696d5f845cd864fc63c5d51","src/bindings/mod.rs":"949f323d6eb5c018497103dbb9dcffb8f395eb5960694b551a24b4887e853afb","src/bindings/python/gen_python/callback_interface.rs":"5df3e091d3c88ef7645e570f693942161a9b9c6307419c15a2534fbc5da974af","src/bindings/python/gen_python/compounds.rs":"9b7187d35826e1b12dbc2b16a13aec783a51f0952e3e2d24adaefbd0ac005016","src/bindings/python/gen_python/custom.rs":"81501641648eb638f5a338c01a71db0d0e96601c3dda83acdb2d49072b387d42","src/bindings/python/gen_python/enum_.rs":"7c3f8f6a97c1491175c8b93b8f9ab13748e2f8084bb717836b6935d024805439","src/bindings/python/gen_python/error.rs":"161bd2e041e3a63a91899de173eec8450cc10e1e9552d064969aa72a02fdfd5e","src/bindings/python/gen_python/executor.rs":"dbbf2292c79f73dacb317a8645185e42f328a017951662975c0488399c562058","src/bindings/python/gen_python/external.rs":"0325e9a39645eb5454d716d4db76a4a31083ddfafa8e9ca063257292372a0637","src/bindings/python/gen_python/miscellany.rs":"d6f6305dd0af85b7ba87b70cbe6ecba00c83d5082c5bdcaf25962fff853973ea","src/bindings/python/gen_python/mod.rs":"4ac0dc0fd9aaabf2e1f9245d13e0090ee0e9c1235ef203bec9314cac5974e9f0","src/bindings/python/gen_python/object.rs":"a4d4c20a0a52687feff2b9a547a13aa9bda09b3af9ec26508646658a88eec8b3","src/bindings/python/gen_python/primitives.rs":"b830c68e20d8539b8ac5566f1ca0dd262c1b14712a747f79e70004cd8f409ba1","src/bindings/python/gen_python/record.rs":"f8e12ce43d7e0f37f05420a849e7867b7251f9790933609a4cb99050fd063089","src/bindings/python/mod.rs":"eac32ce383460d58d3ccf1d406173465fc8a1db8a24408df67620b7d14dcd0cd","src/bindings/python/templates/Async.py":"4a35a878883a548f3bbed929a9ec74c133e2e9cf08375989503e73ddc2f9c648","src/bindings/python/templates/BooleanHelper.py":"c19e38ae3daa29a831f2394a0a2e74c924711e55ddc85db8ac9b5b8b6da9cd92","src/bindings/python/templates/BytesHelper.py":"e8fb9919acc784fb056bba4ab8d5c04ca7b2275211f8397ef2a391833e3d5e8f","src/bindings/python/templates/CallbackInterfaceRuntime.py":"795d8826d5d2b397a91c531c6b1b76d9425728efdcb90514170c8c4f35053e40","src/bindings/python/templates/CallbackInterfaceTemplate.py":"3f38e7b290fce198d188a63dcfa74486810153816283e683d6e04896c2dbea9a","src/bindings/python/templates/CustomType.py":"12064dde5e1baf4d78e541837c414cdc7ee9e827a284c54a98ac92dfaf3478e8","src/bindings/python/templates/DurationHelper.py":"271c301bc480cd48d5df2aec15789dd360f4d3098a9f360d7f8f33fa0a7fcd0a","src/bindings/python/templates/EnumTemplate.py":"1cbc2206f045c3050be1912df581a5393d6f0a4a79c96d8b49661696d25830e0","src/bindings/python/templates/ErrorTemplate.py":"f9ab6c910024e88ff92a7575d5d00cdafe448b2e85d07a9edea57ae7b6dc5864","src/bindings/python/templates/ExternalTemplate.py":"ed4d65caf2de3fd2c2a3fd2658eb44cf91cd2f0878c017be63afa4394bf56be3","src/bindings/python/templates/Float32Helper.py":"80c0a0619d2c58c100ea8db37125878c8e8cf56c42f77195aa9b4b6b6d5716c8","src/bindings/python/templates/Float64Helper.py":"62c3ed0d646d3383c890d1f8fd7cb8639433971b9ba9261ac43c1391472eb141","src/bindings/python/templates/ForeignExecutorTemplate.py":"6a7903acc65b9dac17524767d94b142d38d25d5f5bb27133ee9fd7ed8fb5f5a9","src/bindings/python/templates/Helpers.py":"3265eeb5917e0090a7dbd50fdbd12e7d1b1832a58b347cd003ecf8a433c9ebcd","src/bindings/python/templates/Int16Helper.py":"ef7fd0035a80aef556bdbfbcf074751d4e25661f4e07f9bf41f48601d171e5aa","src/bindings/python/templates/Int32Helper.py":"af7e0176ed41260089426498946e47565a7d57e98dffaae4562dfe541c3019d1","src/bindings/python/templates/Int64Helper.py":"171908319be9edcfe3b178d1d74f0173df2aae6a4a92895a2079fa476caed7df","src/bindings/python/templates/Int8Helper.py":"d02a4a5452ec1096b1b1953e4d661d699f9f8f0ce5086a6f3577a0119f479666","src/bindings/python/templates/MapTemplate.py":"fd0bd7e396a6288a16ecb3dae087ab725be556789887a4dc0c00ab97d815f3fb","src/bindings/python/templates/NamespaceLibraryTemplate.py":"b78b7161d43a95f5a0b5d7da6cae0d8bf47017c6c77ad210e15be9531413baa9","src/bindings/python/templates/ObjectTemplate.py":"3af0c737d1b482169d62dee1b6c49f1a18ea3f485e9fc323b070f35cf00c242c","src/bindings/python/templates/OptionalTemplate.py":"59df962441fb1c50cb99be014c87ecf69450c1a3b60fa6763bd40e9e948124b1","src/bindings/python/templates/PointerManager.py":"22faf6a2801cf756f3b09415b597f0cd403a3872ac99a7e44e3b7b6217606cd7","src/bindings/python/templates/RecordTemplate.py":"04fcbd662bc9817597366046e09321d2516eb8240e796dd9b6f971c347475429","src/bindings/python/templates/RustBufferHelper.py":"8a8c20d195534e465a173dc778ae98957c50e209ec824af2d2b143f5ba6061f5","src/bindings/python/templates/RustBufferTemplate.py":"f5e247b0f8988f29ce94ab50b5fe7749d0423cda1d37b6145cc8a6c5a9818449","src/bindings/python/templates/SequenceTemplate.py":"047f19074fe08982b59001da2ba7318b331ce431d73503e111330579a3ba065f","src/bindings/python/templates/StringHelper.py":"a3f874ea9330413e854c2ebbeff5507e32a166de6967c5cea63ede1f021e267a","src/bindings/python/templates/TimestampHelper.py":"de099ce51ceaa86519c28bb38e21933ead36ff341f4907695029212bcdfed3ac","src/bindings/python/templates/TopLevelFunctionTemplate.py":"93b6101fae2cafdf1a9325bed07019609ac35bacef2dc31ba4be5c256d827473","src/bindings/python/templates/Types.py":"feb69d895e9279e52479146e1dfe2fec48c547378ef2cc0fb988f6acaf6bcc63","src/bindings/python/templates/UInt16Helper.py":"5fbb30ece1f9a2680b60baf680ec4e2936d64de2ff107018e751ef1c041443ef","src/bindings/python/templates/UInt32Helper.py":"84207c380e38a38bb919d58769384a0f4fa175ebbd04ac451b37ccfe01ff68a1","src/bindings/python/templates/UInt64Helper.py":"4606f381834740319a9f604a418ba149917a6dbd43d3d3d8da50c655893e2c8e","src/bindings/python/templates/UInt8Helper.py":"aecf7cf08b7dc75fe81e8dcac78dfce166b132d5c20b4301d845c479ab9f49ba","src/bindings/python/templates/macros.py":"7d0d08f418edf65ff365bf1fb37e3132aebb720dfecdcef3e3ce50529fe0eb6b","src/bindings/python/templates/wrapper.py":"91e8cbf18e5b7d0b2be31c0e09b230318d19406c316b453dab973341eb2c6add","src/bindings/python/test.rs":"48e93959ce3e34ff0191126416301b170239d3e2665711da786e0b8b7a90a2ab","src/bindings/ruby/gen_ruby/mod.rs":"7f3a94537c331a941e6e010e35563247f11f1fedaf971cb8538e17797cb17efa","src/bindings/ruby/gen_ruby/tests.rs":"7dcb86b08e643c43503f4cac6396833497f6988b004321c0067700ee29ffbf32","src/bindings/ruby/mod.rs":"0fdfab5306dc5c05fbcbfb273340d96ad70c5caf5074834ad6851af1a9a56734","src/bindings/ruby/templates/EnumTemplate.rb":"5480edb347f5829e478d19474691babd72f37616ed846d519b5a61cb1d6cf047","src/bindings/ruby/templates/ErrorTemplate.rb":"301c177e639f0a27f19d4935c5317e672aadecbee2f9bfa778df982320f5148d","src/bindings/ruby/templates/Helpers.rb":"ce7ed4be97dad507b991c69c28dc7bb6427e5e79a4b2fba9dad9dccabc3e090c","src/bindings/ruby/templates/NamespaceLibraryTemplate.rb":"9a24c427b9eba99d9e13181a5559a385b5d1d16beae2b72a402f2645b22a9048","src/bindings/ruby/templates/ObjectTemplate.rb":"0cfd9438e4821cf2164b23d748b3227a8cffbe2fab5b7eb70832228ccb628ee0","src/bindings/ruby/templates/RecordTemplate.rb":"4aeff886928ca972e5dc9b799581b30c66a6f6dce446af3285dd3ed6b422dea9","src/bindings/ruby/templates/RustBufferBuilder.rb":"8da4e425b36dde4f171b238cbe57e02fb55e91a45a82134c1dccc0fc360733c0","src/bindings/ruby/templates/RustBufferStream.rb":"43ad2defc772fd24b68df0736533c26597ba007e89b6a5ba0d31fbe356648151","src/bindings/ruby/templates/RustBufferTemplate.rb":"405a32592cab145175b64e21398f83e6e0f16354552c0395479270e732910e08","src/bindings/ruby/templates/TopLevelFunctionTemplate.rb":"88213e7e25bef664da939c04dd5621f438af735ffcb4d2d0c24a529538630069","src/bindings/ruby/templates/macros.rb":"79d7d0e9af749dadbf242f37c0f86af7c616ea5318da127747def40f6cdb20d1","src/bindings/ruby/templates/wrapper.rb":"f82b41543546f8e5804cd0e1785f4735d9dd95383566d0e5ba1cd4d9e8c0578d","src/bindings/ruby/test.rs":"d19837119725233bd9971ca2dfc3256156071c64e6dfaf07ad2307432c055bbb","src/bindings/swift/gen_swift/callback_interface.rs":"6b51276350f506f96fefd0ae8cb3afdcd514e8a529d9e982afc68cbf68d74578","src/bindings/swift/gen_swift/compounds.rs":"1aba37cf2f438423a4ce476eea6a36f71f1d5daddbb77c88556bc3abde287ca7","src/bindings/swift/gen_swift/custom.rs":"bddb601b4ea8810ecbad01271d5ec0b3958999b09bc9382c83637dfd43451734","src/bindings/swift/gen_swift/enum_.rs":"87be67ec3394616368d9ef8e99b7f234c053b3bee9a7f9e6f2dff37f147c8837","src/bindings/swift/gen_swift/executor.rs":"ab672e2d05acbc2c4a839af22034aa557d5e69f1d9c913158310ea1e93851557","src/bindings/swift/gen_swift/external.rs":"321974136d58e649e60b2a3f70a369dce2d49f474f79579f8e0d66eb63d2d634","src/bindings/swift/gen_swift/miscellany.rs":"7fc2444596d76545ad82ee6c4bed64a29dd4a0438d50bfaafe511f41f6a0e409","src/bindings/swift/gen_swift/mod.rs":"41e4bf2fbe622d0dba85363455e287e00dc48e4043910cef35c30ce170acf52b","src/bindings/swift/gen_swift/object.rs":"2269f65a6b58a24bd08fedb133a38b37663bcf11d0586c50a67028022706a156","src/bindings/swift/gen_swift/primitives.rs":"c8346601008ac6a6d07f08ec7395182c45a4d86c163dc1d6d9c326c49f2acda1","src/bindings/swift/gen_swift/record.rs":"5ad98ab04a5d8178daf0956db819c87d26aae7bf968184e88d512e34c02feb90","src/bindings/swift/mod.rs":"26ba270cb7913661f3cee703038d1ea4a70bff64c3b31351d6bc77e67cdee20d","src/bindings/swift/templates/Async.swift":"84b9be2b5eca2dcfad7eee0cb8d34fec613a4bfdc8a7170b8d11575e457f567b","src/bindings/swift/templates/BooleanHelper.swift":"f02e391bed44ca0e03c66c4e6a1545caaae490fc72c4cf5935e66220082a8c30","src/bindings/swift/templates/BridgingHeaderTemplate.h":"3f468869e77b9293836822b8f2ac348716ab5d487f7b8fef1a87ec30ddafa8d5","src/bindings/swift/templates/CallbackInterfaceRuntime.swift":"2c71ac715ad0bca6f73559748453ba37ca242c90de38f76876989be05d21c49b","src/bindings/swift/templates/CallbackInterfaceTemplate.swift":"790f50b49d5b07dd44e8b215ed1fff02991c1f65aba9a9a9925275a544348813","src/bindings/swift/templates/CustomType.swift":"71520eb38a4be9035dca9e3e0402f386e7eaa79b28568bbc2f20d3fd53b4544d","src/bindings/swift/templates/DataHelper.swift":"df11547a2df57dcca0ff9cddc691bb5fa07d5ffd3d328d1c3b4443078008b111","src/bindings/swift/templates/DurationHelper.swift":"cbc41aaa58bda6c2313ede36a9f656a01a28f9c72aa1624e0e1c1da7b841ffb6","src/bindings/swift/templates/EnumTemplate.swift":"fe205dd28defea8ed6126a45b2a95240a920dfebda8927134a50c3b6d0d7e9d7","src/bindings/swift/templates/ErrorTemplate.swift":"3dddb278763b75b38294c1165522fa91078a951ce05c91fbdfde43b5a097f34f","src/bindings/swift/templates/Float32Helper.swift":"ea32538058c4b3c72b1cd2530ac00d0349fadab5e1bc617d33aae4c87692fc98","src/bindings/swift/templates/Float64Helper.swift":"e27e9424dc6e97b8cacc6ca4c796dd2d16dcfcb877e2f19c45eca03381a41e78","src/bindings/swift/templates/ForeignExecutorTemplate.swift":"205933825e691fec525286d263ea34d592cc462257764ee76325bf98cb3cd240","src/bindings/swift/templates/Helpers.swift":"a88fd909787b855998671e551cdb3284109e2fd2b2e7492b1c93c82aad0e9d35","src/bindings/swift/templates/Int16Helper.swift":"204906911813a3931436057c23032f4c4e39e023df90d641d6c6086aefe2f820","src/bindings/swift/templates/Int32Helper.swift":"0997f059c9c4edd3c41aee0bbad4aa2bda6d791a0d623ad8014d5aa6bdae718d","src/bindings/swift/templates/Int64Helper.swift":"bcf8c2deebb3ee9bce87735adc4bd100981989943b69f6a7fb499a9aec4c25d9","src/bindings/swift/templates/Int8Helper.swift":"ad1ec0fa213724933fa4dc4e2e304e13ac4722b774bfffac44793986b997dd33","src/bindings/swift/templates/MapTemplate.swift":"53971ec388417b02519f8deb8d66361ab4693eae77d116f6051cbea4738054ec","src/bindings/swift/templates/ModuleMapTemplate.modulemap":"99ad1e9bf550a21497296f9248ecd4385dd6d0b5892951d24cf990cdbf3eec2c","src/bindings/swift/templates/ObjectTemplate.swift":"4633572ac6d27a0f82f3b125c2136ad4fa126391c0b64b5db1bde4b04a77f807","src/bindings/swift/templates/OptionalTemplate.swift":"2376487ceadca3975f0e82ddf6ce61af8bbbf5b0592fa9cd977460f148d8c99d","src/bindings/swift/templates/RecordTemplate.swift":"16e0b98354b624a8922d7d384a005fa660a6a388d70381872ebbcd0de9fb78a4","src/bindings/swift/templates/RustBufferTemplate.swift":"f4422fdf0cb5b4db267d461f063dedc319ea1a5a13bae1b82c3f108ba8c658bb","src/bindings/swift/templates/SequenceTemplate.swift":"8425b279197582a94b4cf363ab0463907a68a624e24045720ef7df2bcacf3383","src/bindings/swift/templates/StringHelper.swift":"968b9b9b7fbe06a2ac2143016edaff3552e201652accb8d613b03645f0d24a90","src/bindings/swift/templates/TimestampHelper.swift":"82eece13aa186c8e3745c8ad2f1290639ca9689573018a2bdc5c75afbae58c26","src/bindings/swift/templates/TopLevelFunctionTemplate.swift":"ffe0287861e67dcad2be77f30c00c0a326ab59ffbd37409de3bafc969d49df26","src/bindings/swift/templates/Types.swift":"98c654bfc5d2d4ece965cfe15b00e7151b815e26bfb55abf17e799efffccc2c0","src/bindings/swift/templates/UInt16Helper.swift":"d6fba577324fc0e9e50329c968df99341de418011be126bd29702f8a94d87c02","src/bindings/swift/templates/UInt32Helper.swift":"5e0cf151a0c40098b3d96815ba3de23e15fe52f3c517577e1b0c7e7a4c12428f","src/bindings/swift/templates/UInt64Helper.swift":"17237b38d09ced8d2a8ff1ad9ca86873a19e417280e0e60f33d7063397ea4b7b","src/bindings/swift/templates/UInt8Helper.swift":"c4cb2ee4a78b54ca8d0013383c6b43e9ecd42776e3dc7d6e40086325d41714e5","src/bindings/swift/templates/macros.swift":"438091831b355b0ba6726dab7c17c0687ca58854c7799e946a8012e95a42f4ba","src/bindings/swift/templates/wrapper.swift":"d83a1b8ac3ffc761d4e560adae57d5ad275e0fd1bf3fdc35f3b3b3699317c6e6","src/bindings/swift/test.rs":"c15d19e7f324613e2dbd7995dffba875ed430919a0882f05e8e1f6cc8aea613c","src/interface/callbacks.rs":"34384f1a4e89cd30e2c35beab2bbd8cc0a9e3dd21ed0b390859610fbe209b16a","src/interface/enum_.rs":"3a4f9e77d80128444a8a226ef1e5ad7cd339f8d815aa7012554cf94c2e4edd98","src/interface/ffi.rs":"fa23a2e6fcd89d956523bd0aa5c946138ac629752f0be9085e09f78aade75fac","src/interface/function.rs":"835ee542cb19c67fb95502a790771e54deb712272baed8bdc3f6bfabd9c69d6f","src/interface/mod.rs":"5bd3b5a2dd91382089323a21d4d0419dd5621799add4786a4710df0afebcca69","src/interface/object.rs":"2364c4e7f887d6e4256d065f9ad049ffad19f92fe1c1d76789c33a22376bdd7f","src/interface/record.rs":"931dbaa8cb440debfcf14d51be3e6c517ba2c28655033ad2486e384a9bea25c4","src/interface/universe.rs":"66deaa33394e401e3005670731a0685068302fc01640655335a7cbe9fb4cf48e","src/lib.rs":"64a6239dbaa8196089600e7b0c577b43eefc4a9935893292298bf400fd77a03d","src/library_mode.rs":"89c9fc47db09ccb779fd2842d3c7e07b7863164bb5585eeaf959490ca5555438","src/macro_metadata/ci.rs":"07482b87bf5912277d114b24ad3e560cac94ca0087bd6ee9bee2c328d992bb18","src/macro_metadata/extract.rs":"a106a5b6ad8e5deba474646162b83ec4065796c58c60fc13dfbf1a72ed713833","src/macro_metadata/mod.rs":"bcb5e9a015510e9d74c288da928a4bfb8d80926a8ff85227c0eae8cdb2605519","src/scaffolding/mod.rs":"65749e72181c63edae55d49493aa49a1efece93c0a27deda230f5de4b9ba7d60","src/scaffolding/templates/CallbackInterfaceTemplate.rs":"0581f257c0eb7f0be922ef3ebf7892aafad15e9dc7865e53fc9396375f3188fb","src/scaffolding/templates/Checksums.rs":"ee926e840875c2e48e1d0cc5185c11f7a1ed3bde5264b07540812cb13c1d7481","src/scaffolding/templates/EnumTemplate.rs":"350cdcb4f23be6e6e2b442e0d4ea65549bb35a407bef1ac745a37a2e2b527fae","src/scaffolding/templates/ErrorTemplate.rs":"b93e8bc08d818fbf8976b766635ae192042b78c85f8086d4ee41ae03ab7f3b6f","src/scaffolding/templates/ExternalTypesTemplate.rs":"6cf8a89d9e6f1b6f5af4bc86e49454323fa4981846ec76d6661fcff41c348a8e","src/scaffolding/templates/ObjectTemplate.rs":"df614156bee529fd28905a6ad2270685e51736eade6af856edba5de6e9484141","src/scaffolding/templates/RecordTemplate.rs":"5b0f351739d5770f874fb7da56700c557df1d73ac219f3b18c4212d26fc422e0","src/scaffolding/templates/ReexportUniFFIScaffolding.rs":"aa8a1ffa98b6033707d965f90b5709474ed6bc79486fb47dacae8417fc056cf8","src/scaffolding/templates/TopLevelFunctionTemplate.rs":"96b99b38d074492673797737ddac0683c803a3908e03cc9b999d16f7a76ed178","src/scaffolding/templates/UdlMetadata.rs":"d7c50af1de92ef85630b385a910c7b29875502d622eb90da5541a7012b93d9e2","src/scaffolding/templates/macros.rs":"ea6bacd8dd9116ad739bdafe893d70407050f35e4a7ac8dd2c78b8ef34263e8e","src/scaffolding/templates/scaffolding_template.rs":"c8e18306a73ec5b764f665660fc5c91d498b63b6c3f489e524b2bae50f81f231"},"package":"fd992f2929a053829d5875af1eff2ee3d7a7001cb3b9a46cc7895f2caede6940"} \ No newline at end of file diff --git a/third_party/rust/uniffi_bindgen/Cargo.toml b/third_party/rust/uniffi_bindgen/Cargo.toml index f0c7af866550..9469a9cf25e0 100644 --- a/third_party/rust/uniffi_bindgen/Cargo.toml +++ b/third_party/rust/uniffi_bindgen/Cargo.toml @@ -12,12 +12,11 @@ [package] edition = "2021" name = "uniffi_bindgen" -version = "0.27.1" +version = "0.25.3" authors = ["Firefox Sync Team "] description = "a multi-language bindings generator for rust (codegen and cli tooling)" homepage = "https://mozilla.github.io/uniffi-rs" documentation = "https://mozilla.github.io/uniffi-rs" -readme = "README.md" keywords = [ "ffi", "bindgen", @@ -55,7 +54,7 @@ version = "2.7.0" version = "0.3" [dependencies.goblin] -version = "0.8" +version = "0.6" [dependencies.heck] version = "0.4" @@ -68,19 +67,15 @@ version = "1.0" [dependencies.serde] version = "1" -features = ["derive"] - -[dependencies.textwrap] -version = "0.16" [dependencies.toml] version = "0.5" [dependencies.uniffi_meta] -version = "=0.27.1" +version = "=0.25.3" [dependencies.uniffi_testing] -version = "=0.27.1" +version = "=0.25.3" [dependencies.uniffi_udl] -version = "=0.27.1" +version = "=0.25.3" diff --git a/third_party/rust/uniffi_bindgen/README.md b/third_party/rust/uniffi_bindgen/README.md deleted file mode 100644 index 64ac3486a3bf..000000000000 --- a/third_party/rust/uniffi_bindgen/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# UniFFI - a multi-language bindings generator for Rust - -UniFFI is a toolkit for building cross-platform software components in Rust. - -For the impatient, see [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/) -or [**the UniFFI examples**](https://github.com/mozilla/uniffi-rs/tree/main/examples#example-uniffi-components). - -By writing your core business logic in Rust and describing its interface in an "object model", -you can use UniFFI to help you: - -* Compile your Rust code into a shared library for use on different target platforms. -* Generate bindings to load and use the library from different target languages. - -You can describe your object model in an [interface definition file](https://mozilla.github.io/uniffi-rs/udl_file_spec.html) -or [by using proc-macros](https://mozilla.github.io/uniffi-rs/proc_macro/index.html). - -UniFFI is currently used extensively by Mozilla in Firefox mobile and desktop browsers; -written once in Rust, auto-generated bindings allow that functionality to be called -from both Kotlin (for Android apps) and Swift (for iOS apps). -It also has a growing community of users shipping various cool things to many users. - -UniFFI comes with support for **Kotlin**, **Swift**, **Python** and **Ruby** with 3rd party bindings available for **C#** and **Golang**. -Additional foreign language bindings can be developed externally and we welcome contributions to list them here. -See [Third-party foreign language bindings](#third-party-foreign-language-bindings). - -## User Guide - -You can read more about using the tool in [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/). - -We consider it ready for production use, but UniFFI is a long way from a 1.0 release with lots of internal work still going on. -We try hard to avoid breaking simple consumers, but more advanced things might break as you upgrade over time. - -### Etymology and Pronunciation - -ˈjuːnɪfaɪ. Pronounced to rhyme with "unify". - -A portmanteau word that also puns with "unify", to signify the joining of one codebase accessed from many languages. - -uni - [Latin ūni-, from ūnus, one] -FFI - [Abbreviation, Foreign Function Interface] - -## Alternative tools - -Other tools we know of which try and solve a similarly shaped problem are: - -* [Diplomat](https://github.com/rust-diplomat/diplomat/) - see our [writeup of - the different approach taken by that tool](docs/diplomat-and-macros.md) -* [Interoptopus](https://github.com/ralfbiedert/interoptopus/) - -(Please open a PR if you think other tools should be listed!) - -## Third-party foreign language bindings - -* [Kotlin Multiplatform support](https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings). The repository contains Kotlin Multiplatform bindings generation for UniFFI, letting you target both JVM and Native. -* [Go bindings](https://github.com/NordSecurity/uniffi-bindgen-go) -* [C# bindings](https://github.com/NordSecurity/uniffi-bindgen-cs) -* [Dart bindings](https://github.com/NiallBunting/uniffi-rs-dart) - -### External resources - -There are a few third-party resources that make it easier to work with UniFFI: - -* [Plugin support for `.udl` files](https://github.com/Lonami/uniffi-dl) for the IDEA platform ([*uniffi-dl* in the JetBrains marketplace](https://plugins.jetbrains.com/plugin/20527-uniffi-dl)). It provides syntax highlighting, code folding, code completion, reference resolution and navigation (among others features) for the [UniFFI Definition Language (UDL)](https://mozilla.github.io/uniffi-rs/). -* [cargo swift](https://github.com/antoniusnaumann/cargo-swift), a cargo plugin to build a Swift Package from Rust code. It provides an init command for setting up a UniFFI crate and a package command for building a Swift package from Rust code - without the need for additional configuration or build scripts. -* [Cargo NDK Gradle Plugin](https://github.com/willir/cargo-ndk-android-gradle) allows you to build Rust code using [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk), which generally makes Android library builds less painful. -* [`uniffi-starter`](https://github.com/ianthetechie/uniffi-starter) is a minimal project demonstrates a wide range of UniFFI in a complete project in a compact manner. It includes a full Android library build process, an XCFramework generation script, and example Swift package structure. - -(Please open a PR if you think other resources should be listed!) - -## Contributing - -If this tool sounds interesting to you, please help us develop it! You can: - -* View the [contributor guidelines](./docs/contributing.md). -* File or work on [issues](https://github.com/mozilla/uniffi-rs/issues) here in GitHub. -* Join discussions in the [#uniffi:mozilla.org](https://matrix.to/#/#uniffi:mozilla.org) - room on Matrix. - -## Code of Conduct - -This project is governed by Mozilla's [Community Participation Guidelines](./CODE_OF_CONDUCT.md). diff --git a/third_party/rust/uniffi_bindgen/src/backend/filters.rs b/third_party/rust/uniffi_bindgen/src/backend/filters.rs index f4dde0e4203e..0d2da8cab2ea 100644 --- a/third_party/rust/uniffi_bindgen/src/backend/filters.rs +++ b/third_party/rust/uniffi_bindgen/src/backend/filters.rs @@ -13,12 +13,12 @@ use std::fmt; // Need to define an error that implements std::error::Error, which neither String nor // anyhow::Error do. #[derive(Debug)] -pub struct UniFFIError { +struct UniFFIError { message: String, } impl UniFFIError { - pub fn new(message: String) -> Self { + fn new(message: String) -> Self { Self { message } } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs index ae4bffc9732f..e20020e87c72 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs @@ -26,6 +26,6 @@ impl CodeType for CallbackInterfaceCodeType { } fn initialization_fn(&self) -> Option { - Some(format!("uniffiCallbackInterface{}.register", self.id)) + Some(format!("{}.register", self.ffi_converter_name())) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/compounds.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/compounds.rs dissimilarity index 61% index 8d075bbedb92..4329f32f4c37 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/compounds.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/compounds.rs @@ -1,127 +1,98 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use super::{AsCodeType, CodeType}; -use crate::backend::{Literal, Type}; -use crate::ComponentInterface; - -#[derive(Debug)] -pub struct OptionalCodeType { - inner: Type, -} - -impl OptionalCodeType { - pub fn new(inner: Type) -> Self { - Self { inner } - } - fn inner(&self) -> &Type { - &self.inner - } -} - -impl CodeType for OptionalCodeType { - fn type_label(&self, ci: &ComponentInterface) -> String { - format!( - "{}?", - super::KotlinCodeOracle.find(self.inner()).type_label(ci) - ) - } - - fn canonical_name(&self) -> String { - format!( - "Optional{}", - super::KotlinCodeOracle.find(self.inner()).canonical_name() - ) - } - - fn literal(&self, literal: &Literal, ci: &ComponentInterface) -> String { - match literal { - Literal::None => "null".into(), - Literal::Some { inner } => super::KotlinCodeOracle.find(&self.inner).literal(inner, ci), - _ => panic!("Invalid literal for Optional type: {literal:?}"), - } - } -} - -#[derive(Debug)] -pub struct SequenceCodeType { - inner: Type, -} - -impl SequenceCodeType { - pub fn new(inner: Type) -> Self { - Self { inner } - } - fn inner(&self) -> &Type { - &self.inner - } -} - -impl CodeType for SequenceCodeType { - fn type_label(&self, ci: &ComponentInterface) -> String { - format!( - "List<{}>", - super::KotlinCodeOracle.find(self.inner()).type_label(ci) - ) - } - - fn canonical_name(&self) -> String { - format!( - "Sequence{}", - super::KotlinCodeOracle.find(self.inner()).canonical_name() - ) - } - - fn literal(&self, literal: &Literal, _ci: &ComponentInterface) -> String { - match literal { - Literal::EmptySequence => "listOf()".into(), - _ => panic!("Invalid literal for List type: {literal:?}"), - } - } -} - -#[derive(Debug)] -pub struct MapCodeType { - key: Type, - value: Type, -} - -impl MapCodeType { - pub fn new(key: Type, value: Type) -> Self { - Self { key, value } - } - - fn key(&self) -> &Type { - &self.key - } - - fn value(&self) -> &Type { - &self.value - } -} - -impl CodeType for MapCodeType { - fn type_label(&self, ci: &ComponentInterface) -> String { - format!( - "Map<{}, {}>", - super::KotlinCodeOracle.find(self.key()).type_label(ci), - super::KotlinCodeOracle.find(self.value()).type_label(ci), - ) - } - - fn canonical_name(&self) -> String { - format!( - "Map{}{}", - self.key().as_codetype().canonical_name(), - self.value().as_codetype().canonical_name(), - ) - } - - fn literal(&self, literal: &Literal, _ci: &ComponentInterface) -> String { - match literal { - Literal::EmptyMap => "mapOf()".into(), - _ => panic!("Invalid literal for Map type: {literal:?}"), - } - } -} +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use super::{AsCodeType, CodeType}; +use crate::backend::{Literal, Type}; +use crate::ComponentInterface; +use paste::paste; + +fn render_literal(literal: &Literal, inner: &Type, ci: &ComponentInterface) -> String { + match literal { + Literal::Null => "null".into(), + Literal::EmptySequence => "listOf()".into(), + Literal::EmptyMap => "mapOf()".into(), + + // For optionals + _ => super::KotlinCodeOracle.find(inner).literal(literal, ci), + } +} + +macro_rules! impl_code_type_for_compound { + ($T:ty, $type_label_pattern:literal, $canonical_name_pattern: literal) => { + paste! { + #[derive(Debug)] + pub struct $T { + inner: Type, + } + + impl $T { + pub fn new(inner: Type) -> Self { + Self { inner } + } + fn inner(&self) -> &Type { + &self.inner + } + } + + impl CodeType for $T { + fn type_label(&self, ci: &ComponentInterface) -> String { + format!($type_label_pattern, super::KotlinCodeOracle.find(self.inner()).type_label(ci)) + } + + fn canonical_name(&self) -> String { + format!($canonical_name_pattern, super::KotlinCodeOracle.find(self.inner()).canonical_name()) + } + + fn literal(&self, literal: &Literal, ci: &ComponentInterface) -> String { + render_literal(literal, self.inner(), ci) + } + } + } + } + } + +impl_code_type_for_compound!(OptionalCodeType, "{}?", "Optional{}"); +impl_code_type_for_compound!(SequenceCodeType, "List<{}>", "Sequence{}"); + +#[derive(Debug)] +pub struct MapCodeType { + key: Type, + value: Type, +} + +impl MapCodeType { + pub fn new(key: Type, value: Type) -> Self { + Self { key, value } + } + + fn key(&self) -> &Type { + &self.key + } + + fn value(&self) -> &Type { + &self.value + } +} + +impl CodeType for MapCodeType { + fn type_label(&self, ci: &ComponentInterface) -> String { + format!( + "Map<{}, {}>", + super::KotlinCodeOracle.find(self.key()).type_label(ci), + super::KotlinCodeOracle.find(self.value()).type_label(ci), + ) + } + + fn canonical_name(&self) -> String { + format!( + "Map{}{}", + self.key().as_codetype().canonical_name(), + self.value().as_codetype().canonical_name(), + ) + } + + fn literal(&self, literal: &Literal, ci: &ComponentInterface) -> String { + render_literal(literal, &self.value, ci) + } +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/executor.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/executor.rs new file mode 100644 index 000000000000..154e12a38109 --- /dev/null +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/executor.rs @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use super::CodeType; +use crate::ComponentInterface; + +#[derive(Debug)] +pub struct ForeignExecutorCodeType; + +impl CodeType for ForeignExecutorCodeType { + fn type_label(&self, _ci: &ComponentInterface) -> String { + // Kotlin uses a CoroutineScope for ForeignExecutor + "CoroutineScope".into() + } + + fn canonical_name(&self) -> String { + "ForeignExecutor".into() + } + + fn initialization_fn(&self) -> Option { + Some("FfiConverterForeignExecutor.register".into()) + } +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/external.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/external.rs index d55c78f760b2..3ecf09d47f5a 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/external.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/external.rs @@ -17,8 +17,8 @@ impl ExternalCodeType { } impl CodeType for ExternalCodeType { - fn type_label(&self, ci: &ComponentInterface) -> String { - super::KotlinCodeOracle.class_name(ci, &self.name) + fn type_label(&self, _ci: &ComponentInterface) -> String { + self.name.clone() } fn canonical_name(&self) -> String { diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/mod.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/mod.rs index c4fc8e0ed6af..1ed0575a9a51 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/mod.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/mod.rs @@ -7,21 +7,20 @@ use std::cell::RefCell; use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::Debug; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; use askama::Template; -use camino::Utf8Path; use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToUpperCamelCase}; use serde::{Deserialize, Serialize}; use crate::backend::TemplateExpression; -use crate::bindings::kotlin; use crate::interface::*; -use crate::{BindingGenerator, BindingsConfig}; +use crate::BindingsConfig; mod callback_interface; mod compounds; mod custom; mod enum_; +mod executor; mod external; mod miscellany; mod object; @@ -29,28 +28,6 @@ mod primitives; mod record; mod variant; -pub struct KotlinBindingGenerator; -impl BindingGenerator for KotlinBindingGenerator { - type Config = Config; - - fn write_bindings( - &self, - ci: &ComponentInterface, - config: &Config, - out_dir: &Utf8Path, - try_format_code: bool, - ) -> Result<()> { - kotlin::write_bindings(config, ci, out_dir, try_format_code) - } - - fn check_library_path(&self, library_path: &Utf8Path, cdylib_name: Option<&str>) -> Result<()> { - if cdylib_name.is_none() { - bail!("Generate bindings for Kotlin requires a cdylib, but {library_path} was given"); - } - Ok(()) - } -} - trait CodeType: Debug { /// The language specific label used to reference this type. This will be used in /// method signatures and property declarations. @@ -96,21 +73,10 @@ trait CodeType: Debug { pub struct Config { package_name: Option, cdylib_name: Option, - generate_immutable_records: Option, #[serde(default)] custom_types: HashMap, #[serde(default)] external_packages: HashMap, - #[serde(default)] - android: bool, - #[serde(default)] - android_cleaner: Option, -} - -impl Config { - pub(crate) fn android_cleaner(&self) -> bool { - self.android_cleaner.unwrap_or(self.android) - } } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -137,11 +103,6 @@ impl Config { "uniffi".into() } } - - /// Whether to generate immutable records (`val` instead of `var`) - pub fn generate_immutable_records(&self) -> bool { - self.generate_immutable_records.unwrap_or(false) - } } impl BindingsConfig for Config { @@ -275,6 +236,7 @@ pub struct KotlinWrapper<'a> { ci: &'a ComponentInterface, type_helper_code: String, type_imports: BTreeSet, + has_async_fns: bool, } impl<'a> KotlinWrapper<'a> { @@ -287,6 +249,7 @@ impl<'a> KotlinWrapper<'a> { ci, type_helper_code, type_imports, + has_async_fns: ci.has_async_fns(), } } @@ -295,6 +258,10 @@ impl<'a> KotlinWrapper<'a> { .iter_types() .map(|t| KotlinCodeOracle.find(t)) .filter_map(|ct| ct.initialization_fn()) + .chain( + self.has_async_fns + .then(|| "uniffiRustFutureContinuationCallback.register".into()), + ) .collect() } @@ -334,12 +301,7 @@ impl KotlinCodeOracle { /// Get the idiomatic Kotlin rendering of a variable name. fn var_name(&self, nm: &str) -> String { - format!("`{}`", self.var_name_raw(nm)) - } - - /// `var_name` without the backticks. Useful for using in `@Structure.FieldOrder`. - pub fn var_name_raw(&self, nm: &str) -> String { - nm.to_string().to_lower_camel_case() + format!("`{}`", nm.to_string().to_lower_camel_case()) } /// Get the idiomatic Kotlin rendering of an individual enum variant. @@ -347,78 +309,14 @@ impl KotlinCodeOracle { nm.to_string().to_shouty_snake_case() } - /// Get the idiomatic Kotlin rendering of an FFI callback function name - fn ffi_callback_name(&self, nm: &str) -> String { - format!("Uniffi{}", nm.to_upper_camel_case()) - } - - /// Get the idiomatic Kotlin rendering of an FFI struct name - fn ffi_struct_name(&self, nm: &str) -> String { - format!("Uniffi{}", nm.to_upper_camel_case()) - } - - fn ffi_type_label_by_value(&self, ffi_type: &FfiType) -> String { - match ffi_type { - FfiType::RustBuffer(_) => format!("{}.ByValue", self.ffi_type_label(ffi_type)), - FfiType::Struct(name) => format!("{}.UniffiByValue", self.ffi_struct_name(name)), - _ => self.ffi_type_label(ffi_type), - } - } - - /// FFI type name to use inside structs - /// - /// The main requirement here is that all types must have default values or else the struct - /// won't work in some JNA contexts. - fn ffi_type_label_for_ffi_struct(&self, ffi_type: &FfiType) -> String { - match ffi_type { - // Make callbacks function pointers nullable. This matches the semantics of a C - // function pointer better and allows for `null` as a default value. - FfiType::Callback(name) => format!("{}?", self.ffi_callback_name(name)), - _ => self.ffi_type_label_by_value(ffi_type), - } - } - - /// Default values for FFI - /// - /// This is used to: - /// - Set a default return value for error results - /// - Set a default for structs, which JNA sometimes requires - fn ffi_default_value(&self, ffi_type: &FfiType) -> String { - match ffi_type { - FfiType::UInt8 | FfiType::Int8 => "0.toByte()".to_owned(), - FfiType::UInt16 | FfiType::Int16 => "0.toShort()".to_owned(), - FfiType::UInt32 | FfiType::Int32 => "0".to_owned(), - FfiType::UInt64 | FfiType::Int64 => "0.toLong()".to_owned(), - FfiType::Float32 => "0.0f".to_owned(), - FfiType::Float64 => "0.0".to_owned(), - FfiType::RustArcPtr(_) => "Pointer.NULL".to_owned(), - FfiType::RustBuffer(_) => "RustBuffer.ByValue()".to_owned(), - FfiType::Callback(_) => "null".to_owned(), - FfiType::RustCallStatus => "UniffiRustCallStatus.ByValue()".to_owned(), - _ => unimplemented!("ffi_default_value: {ffi_type:?}"), - } - } - - fn ffi_type_label_by_reference(&self, ffi_type: &FfiType) -> String { + fn ffi_type_label_by_value(ffi_type: &FfiType) -> String { match ffi_type { - FfiType::Int8 - | FfiType::UInt8 - | FfiType::Int16 - | FfiType::UInt16 - | FfiType::Int32 - | FfiType::UInt32 - | FfiType::Int64 - | FfiType::UInt64 - | FfiType::Float32 - | FfiType::Float64 => format!("{}ByReference", self.ffi_type_label(ffi_type)), - FfiType::RustArcPtr(_) => "PointerByReference".to_owned(), - // JNA structs default to ByReference - FfiType::RustBuffer(_) | FfiType::Struct(_) => self.ffi_type_label(ffi_type), - _ => panic!("{ffi_type:?} by reference is not implemented"), + FfiType::RustBuffer(_) => format!("{}.ByValue", Self::ffi_type_label(ffi_type)), + _ => Self::ffi_type_label(ffi_type), } } - fn ffi_type_label(&self, ffi_type: &FfiType) -> String { + fn ffi_type_label(ffi_type: &FfiType) -> String { match ffi_type { // Note that unsigned integers in Kotlin are currently experimental, but java.nio.ByteBuffer does not // support them yet. Thus, we use the signed variants to represent both signed and unsigned @@ -429,35 +327,19 @@ impl KotlinCodeOracle { FfiType::Int64 | FfiType::UInt64 => "Long".to_string(), FfiType::Float32 => "Float".to_string(), FfiType::Float64 => "Double".to_string(), - FfiType::Handle => "Long".to_string(), FfiType::RustArcPtr(_) => "Pointer".to_string(), FfiType::RustBuffer(maybe_suffix) => { format!("RustBuffer{}", maybe_suffix.as_deref().unwrap_or_default()) } - FfiType::RustCallStatus => "UniffiRustCallStatus.ByValue".to_string(), FfiType::ForeignBytes => "ForeignBytes.ByValue".to_string(), - FfiType::Callback(name) => self.ffi_callback_name(name), - FfiType::Struct(name) => self.ffi_struct_name(name), - FfiType::Reference(inner) => self.ffi_type_label_by_reference(inner), - FfiType::VoidPointer => "Pointer".to_string(), - } - } - - /// Get the name of the interface and class name for an object. - /// - /// If we support callback interfaces, the interface name is the object name, and the class name is derived from that. - /// Otherwise, the class name is the object name and the interface name is derived from that. - /// - /// This split determines what types `FfiConverter.lower()` inputs. If we support callback - /// interfaces, `lower` must lower anything that implements the interface. If not, then lower - /// only lowers the concrete class. - fn object_names(&self, ci: &ComponentInterface, obj: &Object) -> (String, String) { - let class_name = self.class_name(ci, obj.name()); - if obj.has_callback_interface() { - let impl_name = format!("{class_name}Impl"); - (class_name, impl_name) - } else { - (format!("{class_name}Interface"), class_name) + FfiType::ForeignCallback => "ForeignCallback".to_string(), + FfiType::ForeignExecutorHandle => "USize".to_string(), + FfiType::ForeignExecutorCallback => "UniFfiForeignExecutorCallback".to_string(), + FfiType::RustFutureHandle => "Pointer".to_string(), + FfiType::RustFutureContinuationCallback => { + "UniFffiRustFutureContinuationCallbackType".to_string() + } + FfiType::RustFutureContinuationData => "USize".to_string(), } } } @@ -494,11 +376,12 @@ impl AsCodeType for T { Type::Duration => Box::new(miscellany::DurationCodeType), Type::Enum { name, .. } => Box::new(enum_::EnumCodeType::new(name)), - Type::Object { name, imp, .. } => Box::new(object::ObjectCodeType::new(name, imp)), + Type::Object { name, .. } => Box::new(object::ObjectCodeType::new(name)), Type::Record { name, .. } => Box::new(record::RecordCodeType::new(name)), Type::CallbackInterface { name, .. } => { Box::new(callback_interface::CallbackInterfaceCodeType::new(name)) } + Type::ForeignExecutor => Box::new(executor::ForeignExecutorCodeType), Type::Optional { inner_type } => { Box::new(compounds::OptionalCodeType::new(*inner_type)) } @@ -518,7 +401,6 @@ impl AsCodeType for T { mod filters { use super::*; pub use crate::backend::filters::*; - use uniffi_meta::LiteralMetadata; pub(super) fn type_name( as_ct: &impl AsCodeType, @@ -572,52 +454,8 @@ mod filters { Ok(as_ct.as_codetype().literal(literal, ci)) } - // Get the idiomatic Kotlin rendering of an integer. - fn int_literal(t: &Option, base10: String) -> Result { - if let Some(t) = t { - match t { - Type::Int8 | Type::Int16 | Type::Int32 | Type::Int64 => Ok(base10), - Type::UInt8 | Type::UInt16 | Type::UInt32 | Type::UInt64 => Ok(base10 + "u"), - _ => Err(askama::Error::Custom(Box::new(UniFFIError::new( - "Only ints are supported.".to_string(), - )))), - } - } else { - Err(askama::Error::Custom(Box::new(UniFFIError::new( - "Enum hasn't defined a repr".to_string(), - )))) - } - } - - // Get the idiomatic Kotlin rendering of an individual enum variant's discriminant - pub fn variant_discr_literal(e: &Enum, index: &usize) -> Result { - let literal = e.variant_discr(*index).expect("invalid index"); - match literal { - // Kotlin doesn't convert between signed and unsigned by default - // so we'll need to make sure we define the type as appropriately - LiteralMetadata::UInt(v, _, _) => int_literal(e.variant_discr_type(), v.to_string()), - LiteralMetadata::Int(v, _, _) => int_literal(e.variant_discr_type(), v.to_string()), - _ => Err(askama::Error::Custom(Box::new(UniFFIError::new( - "Only ints are supported.".to_string(), - )))), - } - } - pub fn ffi_type_name_by_value(type_: &FfiType) -> Result { - Ok(KotlinCodeOracle.ffi_type_label_by_value(type_)) - } - - pub fn ffi_type_name_for_ffi_struct(type_: &FfiType) -> Result { - Ok(KotlinCodeOracle.ffi_type_label_for_ffi_struct(type_)) - } - - pub fn ffi_default_value(type_: FfiType) -> Result { - Ok(KotlinCodeOracle.ffi_default_value(&type_)) - } - - /// Get the idiomatic Kotlin rendering of a function name. - pub fn class_name(nm: &str, ci: &ComponentInterface) -> Result { - Ok(KotlinCodeOracle.class_name(ci, nm)) + Ok(KotlinCodeOracle::ffi_type_label_by_value(type_)) } /// Get the idiomatic Kotlin rendering of a function name. @@ -630,11 +468,6 @@ mod filters { Ok(KotlinCodeOracle.var_name(nm)) } - /// Get the idiomatic Kotlin rendering of a variable name. - pub fn var_name_raw(nm: &str) -> Result { - Ok(KotlinCodeOracle.var_name_raw(nm)) - } - /// Get a String representing the name used for an individual enum variant. pub fn variant_name(v: &Variant) -> Result { Ok(KotlinCodeOracle.enum_variant_name(v.name())) @@ -645,30 +478,13 @@ mod filters { Ok(KotlinCodeOracle.convert_error_suffix(&name)) } - /// Get the idiomatic Kotlin rendering of an FFI callback function name - pub fn ffi_callback_name(nm: &str) -> Result { - Ok(KotlinCodeOracle.ffi_callback_name(nm)) - } - - /// Get the idiomatic Kotlin rendering of an FFI struct name - pub fn ffi_struct_name(nm: &str) -> Result { - Ok(KotlinCodeOracle.ffi_struct_name(nm)) - } - - pub fn object_names( - obj: &Object, - ci: &ComponentInterface, - ) -> Result<(String, String), askama::Error> { - Ok(KotlinCodeOracle.object_names(ci, obj)) - } - pub fn async_poll( callable: impl Callable, ci: &ComponentInterface, ) -> Result { let ffi_func = callable.ffi_rust_future_poll(ci); Ok(format!( - "{{ future, callback, continuation -> UniffiLib.INSTANCE.{ffi_func}(future, callback, continuation) }}" + "{{ future, continuation -> _UniFFILib.INSTANCE.{ffi_func}(future, continuation) }}" )) } @@ -677,7 +493,7 @@ mod filters { ci: &ComponentInterface, ) -> Result { let ffi_func = callable.ffi_rust_future_complete(ci); - let call = format!("UniffiLib.INSTANCE.{ffi_func}(future, continuation)"); + let call = format!("_UniFFILib.INSTANCE.{ffi_func}(future, continuation)"); let call = match callable.return_type() { Some(Type::External { kind: ExternalKind::DataClass, @@ -686,7 +502,7 @@ mod filters { }) => { // Need to convert the RustBuffer from our package to the RustBuffer of the external package let suffix = KotlinCodeOracle.class_name(ci, &name); - format!("{call}.let {{ RustBuffer{suffix}.create(it.capacity.toULong(), it.len.toULong(), it.data) }}") + format!("{call}.let {{ RustBuffer{suffix}.create(it.capacity, it.len, it.data) }}") } _ => call, }; @@ -699,7 +515,7 @@ mod filters { ) -> Result { let ffi_func = callable.ffi_rust_future_free(ci); Ok(format!( - "{{ future -> UniffiLib.INSTANCE.{ffi_func}(future) }}" + "{{ future -> _UniFFILib.INSTANCE.{ffi_func}(future) }}" )) } @@ -711,13 +527,4 @@ mod filters { pub fn unquote(nm: &str) -> Result { Ok(nm.trim_matches('`').to_string()) } - - /// Get the idiomatic Kotlin rendering of docstring - pub fn docstring(docstring: &str, spaces: &i32) -> Result { - let middle = textwrap::indent(&textwrap::dedent(docstring), " * "); - let wrapped = format!("/**\n{middle}\n */"); - - let spaces = usize::try_from(*spaces).unwrap_or_default(); - Ok(textwrap::indent(&wrapped, &" ".repeat(spaces))) - } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs similarity index 69% copy from third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs copy to third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs index ae4bffc9732f..c39ae59cce9a 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/callback_interface.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs @@ -6,17 +6,17 @@ use super::CodeType; use crate::ComponentInterface; #[derive(Debug)] -pub struct CallbackInterfaceCodeType { +pub struct ObjectCodeType { id: String, } -impl CallbackInterfaceCodeType { +impl ObjectCodeType { pub fn new(id: String) -> Self { Self { id } } } -impl CodeType for CallbackInterfaceCodeType { +impl CodeType for ObjectCodeType { fn type_label(&self, ci: &ComponentInterface) -> String { super::KotlinCodeOracle.class_name(ci, &self.id) } @@ -24,8 +24,4 @@ impl CodeType for CallbackInterfaceCodeType { fn canonical_name(&self) -> String { format!("Type{}", self.id) } - - fn initialization_fn(&self) -> Option { - Some(format!("uniffiCallbackInterface{}.register", self.id)) - } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/primitives.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/primitives.rs index 0bc5a5d99ea2..22495fa20989 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/primitives.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/primitives.rs @@ -9,11 +9,7 @@ use paste::paste; fn render_literal(literal: &Literal, _ci: &ComponentInterface) -> String { fn typed_number(type_: &Type, num_str: String) -> String { - let unwrapped_type = match type_ { - Type::Optional { inner_type } => inner_type, - t => t, - }; - match unwrapped_type { + match type_ { // Bytes, Shorts and Ints can all be inferred from the type. Type::Int8 | Type::Int16 | Type::Int32 => num_str, Type::Int64 => format!("{num_str}L"), @@ -23,7 +19,7 @@ fn render_literal(literal: &Literal, _ci: &ComponentInterface) -> String { Type::Float32 => format!("{num_str}f"), Type::Float64 => num_str, - _ => panic!("Unexpected literal: {num_str} for type: {type_:?}"), + _ => panic!("Unexpected literal: {num_str} is not a number"), } } @@ -60,7 +56,7 @@ macro_rules! impl_code_type_for_primitive { impl CodeType for $T { fn type_label(&self, _ci: &ComponentInterface) -> String { - format!("kotlin.{}", $class_name) + $class_name.into() } fn canonical_name(&self) -> String { diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Async.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Async.kt dissimilarity index 88% index b28fbd2c80da..c6a32655f2b4 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Async.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Async.kt @@ -1,117 +1,44 @@ -// Async return type handlers - -internal const val UNIFFI_RUST_FUTURE_POLL_READY = 0.toByte() -internal const val UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1.toByte() - -internal val uniffiContinuationHandleMap = UniffiHandleMap>() - -// FFI type for Rust future continuations -internal object uniffiRustFutureContinuationCallbackImpl: UniffiRustFutureContinuationCallback { - override fun callback(data: Long, pollResult: Byte) { - uniffiContinuationHandleMap.remove(data).resume(pollResult) - } -} - -internal suspend fun uniffiRustCallAsync( - rustFuture: Long, - pollFunc: (Long, UniffiRustFutureContinuationCallback, Long) -> Unit, - completeFunc: (Long, UniffiRustCallStatus) -> F, - freeFunc: (Long) -> Unit, - liftFunc: (F) -> T, - errorHandler: UniffiRustCallStatusErrorHandler -): T { - try { - do { - val pollResult = suspendCancellableCoroutine { continuation -> - pollFunc( - rustFuture, - uniffiRustFutureContinuationCallbackImpl, - uniffiContinuationHandleMap.insert(continuation) - ) - } - } while (pollResult != UNIFFI_RUST_FUTURE_POLL_READY); - - return liftFunc( - uniffiRustCallWithError(errorHandler, { status -> completeFunc(rustFuture, status) }) - ) - } finally { - freeFunc(rustFuture) - } -} - -{%- if ci.has_async_callback_interface_definition() %} -internal inline fun uniffiTraitInterfaceCallAsync( - crossinline makeCall: suspend () -> T, - crossinline handleSuccess: (T) -> Unit, - crossinline handleError: (UniffiRustCallStatus.ByValue) -> Unit, -): UniffiForeignFuture { - // Using `GlobalScope` is labeled as a "delicate API" and generally discouraged in Kotlin programs, since it breaks structured concurrency. - // However, our parent task is a Rust future, so we're going to need to break structure concurrency in any case. - // - // Uniffi does its best to support structured concurrency across the FFI. - // If the Rust future is dropped, `uniffiForeignFutureFreeImpl` is called, which will cancel the Kotlin coroutine if it's still running. - @OptIn(DelicateCoroutinesApi::class) - val job = GlobalScope.launch { - try { - handleSuccess(makeCall()) - } catch(e: Exception) { - handleError( - UniffiRustCallStatus.create( - UNIFFI_CALL_UNEXPECTED_ERROR, - {{ Type::String.borrow()|lower_fn }}(e.toString()), - ) - ) - } - } - val handle = uniffiForeignFutureHandleMap.insert(job) - return UniffiForeignFuture(handle, uniffiForeignFutureFreeImpl) -} - -internal inline fun uniffiTraitInterfaceCallAsyncWithError( - crossinline makeCall: suspend () -> T, - crossinline handleSuccess: (T) -> Unit, - crossinline handleError: (UniffiRustCallStatus.ByValue) -> Unit, - crossinline lowerError: (E) -> RustBuffer.ByValue, -): UniffiForeignFuture { - // See uniffiTraitInterfaceCallAsync for details on `DelicateCoroutinesApi` - @OptIn(DelicateCoroutinesApi::class) - val job = GlobalScope.launch { - try { - handleSuccess(makeCall()) - } catch(e: Exception) { - if (e is E) { - handleError( - UniffiRustCallStatus.create( - UNIFFI_CALL_ERROR, - lowerError(e), - ) - ) - } else { - handleError( - UniffiRustCallStatus.create( - UNIFFI_CALL_UNEXPECTED_ERROR, - {{ Type::String.borrow()|lower_fn }}(e.toString()), - ) - ) - } - } - } - val handle = uniffiForeignFutureHandleMap.insert(job) - return UniffiForeignFuture(handle, uniffiForeignFutureFreeImpl) -} - -internal val uniffiForeignFutureHandleMap = UniffiHandleMap() - -internal object uniffiForeignFutureFreeImpl: UniffiForeignFutureFree { - override fun callback(handle: Long) { - val job = uniffiForeignFutureHandleMap.remove(handle) - if (!job.isCompleted) { - job.cancel() - } - } -} - -// For testing -public fun uniffiForeignFutureHandleCount() = uniffiForeignFutureHandleMap.size - -{%- endif %} +// Async return type handlers + +internal const val UNIFFI_RUST_FUTURE_POLL_READY = 0.toShort() +internal const val UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1.toShort() + +internal val uniffiContinuationHandleMap = UniFfiHandleMap>() + +// FFI type for Rust future continuations +internal object uniffiRustFutureContinuationCallback: UniFffiRustFutureContinuationCallbackType { + override fun callback(continuationHandle: USize, pollResult: Short) { + uniffiContinuationHandleMap.remove(continuationHandle)?.resume(pollResult) + } + + internal fun register(lib: _UniFFILib) { + lib.{{ ci.ffi_rust_future_continuation_callback_set().name() }}(this) + } +} + +internal suspend fun uniffiRustCallAsync( + rustFuture: Pointer, + pollFunc: (Pointer, USize) -> Unit, + completeFunc: (Pointer, RustCallStatus) -> F, + freeFunc: (Pointer) -> Unit, + liftFunc: (F) -> T, + errorHandler: CallStatusErrorHandler +): T { + try { + do { + val pollResult = suspendCancellableCoroutine { continuation -> + pollFunc( + rustFuture, + uniffiContinuationHandleMap.insert(continuation) + ) + } + } while (pollResult != UNIFFI_RUST_FUTURE_POLL_READY); + + return liftFunc( + rustCallWithError(errorHandler, { status -> completeFunc(rustFuture, status) }) + ) + } finally { + freeFunc(rustFuture) + } +} + diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/BooleanHelper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/BooleanHelper.kt index c6b266066d1b..8cfa2ce0003c 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/BooleanHelper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/BooleanHelper.kt @@ -11,7 +11,7 @@ public object FfiConverterBoolean: FfiConverter { return if (value) 1.toByte() else 0.toByte() } - override fun allocationSize(value: Boolean) = 1UL + override fun allocationSize(value: Boolean) = 1 override fun write(value: Boolean, buf: ByteBuffer) { buf.put(lower(value)) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ByteArrayHelper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ByteArrayHelper.kt index c9449069e26b..4840a199b4b6 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ByteArrayHelper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ByteArrayHelper.kt @@ -5,8 +5,8 @@ public object FfiConverterByteArray: FfiConverterRustBuffer { buf.get(byteArr) return byteArr } - override fun allocationSize(value: ByteArray): ULong { - return 4UL + value.size.toULong() + override fun allocationSize(value: ByteArray): Int { + return 4 + value.size } override fun write(value: ByteArray, buf: ByteBuffer) { buf.putInt(value.size) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt deleted file mode 100644 index 30a39d9afb27..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt +++ /dev/null @@ -1,117 +0,0 @@ -{% if self.include_once_check("CallbackInterfaceRuntime.kt") %}{% include "CallbackInterfaceRuntime.kt" %}{% endif %} - -{%- let trait_impl=format!("uniffiCallbackInterface{}", name) %} - -// Put the implementation in an object so we don't pollute the top-level namespace -internal object {{ trait_impl }} { - {%- for (ffi_callback, meth) in vtable_methods.iter() %} - internal object {{ meth.name()|var_name }}: {{ ffi_callback.name()|ffi_callback_name }} { - override fun callback( - {%- for arg in ffi_callback.arguments() -%} - {{ arg.name().borrow()|var_name }}: {{ arg.type_().borrow()|ffi_type_name_by_value }}, - {%- endfor -%} - {%- if ffi_callback.has_rust_call_status_arg() -%} - uniffiCallStatus: UniffiRustCallStatus, - {%- endif -%} - ) - {%- match ffi_callback.return_type() %} - {%- when Some(return_type) %}: {{ return_type|ffi_type_name_by_value }}, - {%- when None %} - {%- endmatch %} { - val uniffiObj = {{ ffi_converter_name }}.handleMap.get(uniffiHandle) - val makeCall = {% if meth.is_async() %}suspend {% endif %}{ -> - uniffiObj.{{ meth.name()|fn_name() }}( - {%- for arg in meth.arguments() %} - {{ arg|lift_fn }}({{ arg.name()|var_name }}), - {%- endfor %} - ) - } - {%- if !meth.is_async() %} - - {%- match meth.return_type() %} - {%- when Some(return_type) %} - val writeReturn = { value: {{ return_type|type_name(ci) }} -> uniffiOutReturn.setValue({{ return_type|lower_fn }}(value)) } - {%- when None %} - val writeReturn = { _: Unit -> Unit } - {%- endmatch %} - - {%- match meth.throws_type() %} - {%- when None %} - uniffiTraitInterfaceCall(uniffiCallStatus, makeCall, writeReturn) - {%- when Some(error_type) %} - uniffiTraitInterfaceCallWithError( - uniffiCallStatus, - makeCall, - writeReturn, - { e: {{error_type|type_name(ci) }} -> {{ error_type|lower_fn }}(e) } - ) - {%- endmatch %} - - {%- else %} - val uniffiHandleSuccess = { {% if meth.return_type().is_some() %}returnValue{% else %}_{% endif %}: {% match meth.return_type() %}{%- when Some(return_type) %}{{ return_type|type_name(ci) }}{%- when None %}Unit{% endmatch %} -> - val uniffiResult = {{ meth.foreign_future_ffi_result_struct().name()|ffi_struct_name }}.UniffiByValue( - {%- match meth.return_type() %} - {%- when Some(return_type) %} - {{ return_type|lower_fn }}(returnValue), - {%- when None %} - {%- endmatch %} - UniffiRustCallStatus.ByValue() - ) - uniffiResult.write() - uniffiFutureCallback.callback(uniffiCallbackData, uniffiResult) - } - val uniffiHandleError = { callStatus: UniffiRustCallStatus.ByValue -> - uniffiFutureCallback.callback( - uniffiCallbackData, - {{ meth.foreign_future_ffi_result_struct().name()|ffi_struct_name }}.UniffiByValue( - {%- match meth.return_type() %} - {%- when Some(return_type) %} - {{ return_type.into()|ffi_default_value }}, - {%- when None %} - {%- endmatch %} - callStatus, - ), - ) - } - - uniffiOutReturn.uniffiSetValue( - {%- match meth.throws_type() %} - {%- when None %} - uniffiTraitInterfaceCallAsync( - makeCall, - uniffiHandleSuccess, - uniffiHandleError - ) - {%- when Some(error_type) %} - uniffiTraitInterfaceCallAsyncWithError( - makeCall, - uniffiHandleSuccess, - uniffiHandleError, - { e: {{error_type|type_name(ci) }} -> {{ error_type|lower_fn }}(e) } - ) - {%- endmatch %} - ) - {%- endif %} - } - } - {%- endfor %} - - internal object uniffiFree: {{ "CallbackInterfaceFree"|ffi_callback_name }} { - override fun callback(handle: Long) { - {{ ffi_converter_name }}.handleMap.remove(handle) - } - } - - internal var vtable = {{ vtable|ffi_type_name_by_value }}( - {%- for (ffi_callback, meth) in vtable_methods.iter() %} - {{ meth.name()|var_name() }}, - {%- endfor %} - uniffiFree, - ) - - // Registers the foreign callback with the Rust side. - // This method is generated for each callback interface. - internal fun register(lib: UniffiLib) { - lib.{{ ffi_init_callback.name() }}(vtable) - } -} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt index d58a651e2403..62a71e02f15d 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceRuntime.kt @@ -1,3 +1,43 @@ +internal typealias Handle = Long +internal class ConcurrentHandleMap( + private val leftMap: MutableMap = mutableMapOf(), + private val rightMap: MutableMap = mutableMapOf() +) { + private val lock = java.util.concurrent.locks.ReentrantLock() + private val currentHandle = AtomicLong(0L) + private val stride = 1L + + fun insert(obj: T): Handle = + lock.withLock { + rightMap[obj] ?: + currentHandle.getAndAdd(stride) + .also { handle -> + leftMap[handle] = obj + rightMap[obj] = handle + } + } + + fun get(handle: Handle) = lock.withLock { + leftMap[handle] + } + + fun delete(handle: Handle) { + this.remove(handle) + } + + fun remove(handle: Handle): T? = + lock.withLock { + leftMap.remove(handle)?.let { obj -> + rightMap.remove(obj) + obj + } + } +} + +interface ForeignCallback : com.sun.jna.Callback { + public fun callback(handle: Handle, method: Int, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int +} + // Magic number for the Rust proxy to call using the same mechanism as every other method, // to free the callback once it's dropped by Rust. internal const val IDX_CALLBACK_FREE = 0 @@ -6,22 +46,31 @@ internal const val UNIFFI_CALLBACK_SUCCESS = 0 internal const val UNIFFI_CALLBACK_ERROR = 1 internal const val UNIFFI_CALLBACK_UNEXPECTED_ERROR = 2 -public abstract class FfiConverterCallbackInterface: FfiConverter { - internal val handleMap = UniffiHandleMap() +public abstract class FfiConverterCallbackInterface( + protected val foreignCallback: ForeignCallback +): FfiConverter { + private val handleMap = ConcurrentHandleMap() + + // Registers the foreign callback with the Rust side. + // This method is generated for each callback interface. + internal abstract fun register(lib: _UniFFILib) - internal fun drop(handle: Long) { - handleMap.remove(handle) + fun drop(handle: Handle): RustBuffer.ByValue { + return handleMap.remove(handle).let { RustBuffer.ByValue() } } - override fun lift(value: Long): CallbackInterface { - return handleMap.get(value) + override fun lift(value: Handle): CallbackInterface { + return handleMap.get(value) ?: throw InternalException("No callback in handlemap; this is a Uniffi bug") } override fun read(buf: ByteBuffer) = lift(buf.getLong()) - override fun lower(value: CallbackInterface) = handleMap.insert(value) + override fun lower(value: CallbackInterface) = + handleMap.insert(value).also { + assert(handleMap.get(it) === value) { "Handle map is not returning the object we just placed there. This is a bug in the HandleMap." } + } - override fun allocationSize(value: CallbackInterface) = 8UL + override fun allocationSize(value: CallbackInterface) = 8 override fun write(value: CallbackInterface, buf: ByteBuffer) { buf.putLong(lower(value)) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt dissimilarity index 74% index d2cdee4f33f1..5a29f0acc370 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceTemplate.kt @@ -1,13 +1,129 @@ -{%- let cbi = ci|get_callback_interface_definition(name) %} -{%- let ffi_init_callback = cbi.ffi_init_callback() %} -{%- let interface_name = cbi|type_name(ci) %} -{%- let interface_docstring = cbi.docstring() %} -{%- let methods = cbi.methods() %} -{%- let vtable = cbi.vtable() %} -{%- let vtable_methods = cbi.vtable_methods() %} - -{% include "Interface.kt" %} -{% include "CallbackInterfaceImpl.kt" %} - -// The ffiConverter which transforms the Callbacks in to handles to pass to Rust. -public object {{ ffi_converter_name }}: FfiConverterCallbackInterface<{{ interface_name }}>() +{%- let cbi = ci|get_callback_interface_definition(name) %} +{%- let type_name = cbi|type_name(ci) %} +{%- let foreign_callback = format!("ForeignCallback{}", canonical_type_name) %} + +{% if self.include_once_check("CallbackInterfaceRuntime.kt") %}{% include "CallbackInterfaceRuntime.kt" %}{% endif %} +{{- self.add_import("java.util.concurrent.atomic.AtomicLong") }} +{{- self.add_import("java.util.concurrent.locks.ReentrantLock") }} +{{- self.add_import("kotlin.concurrent.withLock") }} + +// Declaration and FfiConverters for {{ type_name }} Callback Interface + +public interface {{ type_name }} { + {% for meth in cbi.methods() -%} + fun {{ meth.name()|fn_name }}({% call kt::arg_list_decl(meth) %}) + {%- match meth.return_type() -%} + {%- when Some with (return_type) %}: {{ return_type|type_name(ci) -}} + {%- else -%} + {%- endmatch %} + {% endfor %} + companion object +} + +// The ForeignCallback that is passed to Rust. +internal class {{ foreign_callback }} : ForeignCallback { + @Suppress("TooGenericExceptionCaught") + override fun callback(handle: Handle, method: Int, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int { + val cb = {{ ffi_converter_name }}.lift(handle) + return when (method) { + IDX_CALLBACK_FREE -> { + {{ ffi_converter_name }}.drop(handle) + // Successful return + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + UNIFFI_CALLBACK_SUCCESS + } + {% for meth in cbi.methods() -%} + {% let method_name = format!("invoke_{}", meth.name())|fn_name -%} + {{ loop.index }} -> { + // Call the method, write to outBuf and return a status code + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` for info + try { + this.{{ method_name }}(cb, argsData, argsLen, outBuf) + } catch (e: Throwable) { + // Unexpected error + try { + // Try to serialize the error into a string + outBuf.setValue({{ Type::String.borrow()|ffi_converter_name }}.lower(e.toString())) + } catch (e: Throwable) { + // If that fails, then it's time to give up and just return + } + UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + } + {% endfor %} + else -> { + // An unexpected error happened. + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + try { + // Try to serialize the error into a string + outBuf.setValue({{ Type::String.borrow()|ffi_converter_name }}.lower("Invalid Callback index")) + } catch (e: Throwable) { + // If that fails, then it's time to give up and just return + } + UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + } + } + + {% for meth in cbi.methods() -%} + {% let method_name = format!("invoke_{}", meth.name())|fn_name %} + @Suppress("UNUSED_PARAMETER") + private fun {{ method_name }}(kotlinCallbackInterface: {{ type_name }}, argsData: Pointer, argsLen: Int, outBuf: RustBufferByReference): Int { + {%- if meth.arguments().len() > 0 %} + val argsBuf = argsData.getByteBuffer(0, argsLen.toLong()).also { + it.order(ByteOrder.BIG_ENDIAN) + } + {%- endif %} + + {%- match meth.return_type() %} + {%- when Some with (return_type) %} + fun makeCall() : Int { + val returnValue = kotlinCallbackInterface.{{ meth.name()|fn_name }}( + {%- for arg in meth.arguments() %} + {{ arg|read_fn }}(argsBuf) + {% if !loop.last %}, {% endif %} + {%- endfor %} + ) + outBuf.setValue({{ return_type|ffi_converter_name }}.lowerIntoRustBuffer(returnValue)) + return UNIFFI_CALLBACK_SUCCESS + } + {%- when None %} + fun makeCall() : Int { + kotlinCallbackInterface.{{ meth.name()|fn_name }}( + {%- for arg in meth.arguments() %} + {{ arg|read_fn }}(argsBuf) + {%- if !loop.last %}, {% endif %} + {%- endfor %} + ) + return UNIFFI_CALLBACK_SUCCESS + } + {%- endmatch %} + + {%- match meth.throws_type() %} + {%- when None %} + fun makeCallAndHandleError() : Int = makeCall() + {%- when Some(error_type) %} + fun makeCallAndHandleError() : Int = try { + makeCall() + } catch (e: {{ error_type|type_name(ci) }}) { + // Expected error, serialize it into outBuf + outBuf.setValue({{ error_type|ffi_converter_name }}.lowerIntoRustBuffer(e)) + UNIFFI_CALLBACK_ERROR + } + {%- endmatch %} + + return makeCallAndHandleError() + } + {% endfor %} +} + +// The ffiConverter which transforms the Callbacks in to Handles to pass to Rust. +public object {{ ffi_converter_name }}: FfiConverterCallbackInterface<{{ type_name }}>( + foreignCallback = {{ foreign_callback }}() +) { + override fun register(lib: _UniFFILib) { + rustCall() { status -> + lib.{{ cbi.ffi_init_callback().name() }}(this.foreignCallback, status) + } + } +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CustomTypeTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CustomTypeTemplate.kt index aeb5f58002ed..04150c5d78c5 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CustomTypeTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CustomTypeTemplate.kt @@ -49,7 +49,7 @@ public object {{ ffi_converter_name }}: FfiConverter<{{ name }}, {{ ffi_type_nam return {{ config.into_custom.render("builtinValue") }} } - override fun allocationSize(value: {{ name }}): ULong { + override fun allocationSize(value: {{ name }}): Int { val builtinValue = {{ config.from_custom.render("value") }} return {{ builtin|allocation_size_fn }}(builtinValue) } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/DurationHelper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/DurationHelper.kt index 62e02607f349..4237c6f9a8cc 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/DurationHelper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/DurationHelper.kt @@ -14,7 +14,7 @@ public object FfiConverterDuration: FfiConverterRustBuffer { } // 8 bytes for seconds, 4 bytes for nanoseconds - override fun allocationSize(value: java.time.Duration) = 12UL + override fun allocationSize(value: java.time.Duration) = 12 override fun write(value: java.time.Duration, buf: ByteBuffer) { if (value.seconds < 0) { diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt index 8d1c2235ece5..d4c4a1684aeb 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/EnumTemplate.kt @@ -7,25 +7,12 @@ {%- if e.is_flat() %} -{%- call kt::docstring(e, 0) %} -{% match e.variant_discr_type() %} -{% when None %} enum class {{ type_name }} { {% for variant in e.variants() -%} - {%- call kt::docstring(variant, 4) %} {{ variant|variant_name }}{% if loop.last %};{% else %},{% endif %} {%- endfor %} companion object } -{% when Some with (variant_discr_type) %} -enum class {{ type_name }}(val value: {{ variant_discr_type|type_name(ci) }}) { - {% for variant in e.variants() -%} - {%- call kt::docstring(variant, 4) %} - {{ variant|variant_name }}({{ e|variant_discr_literal(loop.index0) }}){% if loop.last %};{% else %},{% endif %} - {%- endfor %} - companion object -} -{% endmatch %} public object {{ e|ffi_converter_name }}: FfiConverterRustBuffer<{{ type_name }}> { override fun read(buf: ByteBuffer) = try { @@ -34,7 +21,7 @@ public object {{ e|ffi_converter_name }}: FfiConverterRustBuffer<{{ type_name }} throw RuntimeException("invalid enum value, something is very wrong!!", e) } - override fun allocationSize(value: {{ type_name }}) = 4UL + override fun allocationSize(value: {{ type_name }}) = 4 override fun write(value: {{ type_name }}, buf: ByteBuffer) { buf.putInt(value.ordinal + 1) @@ -43,18 +30,15 @@ public object {{ e|ffi_converter_name }}: FfiConverterRustBuffer<{{ type_name }} {% else %} -{%- call kt::docstring(e, 0) %} sealed class {{ type_name }}{% if contains_object_references %}: Disposable {% endif %} { {% for variant in e.variants() -%} - {%- call kt::docstring(variant, 4) %} {% if !variant.has_fields() -%} object {{ variant|type_name(ci) }} : {{ type_name }}() {% else -%} data class {{ variant|type_name(ci) }}( - {%- for field in variant.fields() -%} - {%- call kt::docstring(field, 8) %} - val {% call kt::field_name(field, loop.index) %}: {{ field|type_name(ci) }}{% if loop.last %}{% else %}, {% endif %} - {%- endfor -%} + {% for field in variant.fields() -%} + val {{ field.name()|var_name }}: {{ field|type_name(ci) }}{% if loop.last %}{% else %}, {% endif %} + {% endfor -%} ) : {{ type_name }}() { companion object } @@ -99,9 +83,9 @@ public object {{ e|ffi_converter_name }} : FfiConverterRustBuffer<{{ type_name } is {{ type_name }}.{{ variant|type_name(ci) }} -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( - 4UL + 4 {%- for field in variant.fields() %} - + {{ field|allocation_size_fn }}(value.{%- call kt::field_name(field, loop.index) -%}) + + {{ field|allocation_size_fn }}(value.{{ field.name()|var_name }}) {%- endfor %} ) } @@ -114,7 +98,7 @@ public object {{ e|ffi_converter_name }} : FfiConverterRustBuffer<{{ type_name } is {{ type_name }}.{{ variant|type_name(ci) }} -> { buf.putInt({{ loop.index }}) {%- for field in variant.fields() %} - {{ field|write_fn }}(value.{%- call kt::field_name(field, loop.index) -%}, buf) + {{ field|write_fn }}(value.{{ field.name()|var_name }}, buf) {%- endfor %} Unit } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ErrorTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ErrorTemplate.kt index 4760c03fd6cf..986db5424d0b 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ErrorTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ErrorTemplate.kt @@ -3,26 +3,24 @@ {%- let canonical_type_name = type_|canonical_name %} {% if e.is_flat() %} -{%- call kt::docstring(e, 0) %} sealed class {{ type_name }}(message: String): Exception(message){% if contains_object_references %}, Disposable {% endif %} { + // Each variant is a nested class + // Flat enums carries a string error message, so no special implementation is necessary. {% for variant in e.variants() -%} - {%- call kt::docstring(variant, 4) %} class {{ variant|error_variant_name }}(message: String) : {{ type_name }}(message) {% endfor %} - companion object ErrorHandler : UniffiRustCallStatusErrorHandler<{{ type_name }}> { + companion object ErrorHandler : CallStatusErrorHandler<{{ type_name }}> { override fun lift(error_buf: RustBuffer.ByValue): {{ type_name }} = {{ ffi_converter_name }}.lift(error_buf) } } {%- else %} -{%- call kt::docstring(e, 0) %} sealed class {{ type_name }}: Exception(){% if contains_object_references %}, Disposable {% endif %} { + // Each variant is a nested class {% for variant in e.variants() -%} - {%- call kt::docstring(variant, 4) %} {%- let variant_name = variant|error_variant_name %} class {{ variant_name }}( {% for field in variant.fields() -%} - {%- call kt::docstring(field, 8) %} val {{ field.name()|var_name }}: {{ field|type_name(ci) }}{% if loop.last %}{% else %}, {% endif %} {% endfor -%} ) : {{ type_name }}() { @@ -31,7 +29,7 @@ sealed class {{ type_name }}: Exception(){% if contains_object_references %}, Di } {% endfor %} - companion object ErrorHandler : UniffiRustCallStatusErrorHandler<{{ type_name }}> { + companion object ErrorHandler : CallStatusErrorHandler<{{ type_name }}> { override fun lift(error_buf: RustBuffer.ByValue): {{ type_name }} = {{ ffi_converter_name }}.lift(error_buf) } @@ -78,15 +76,15 @@ public object {{ e|ffi_converter_name }} : FfiConverterRustBuffer<{{ type_name } {%- endif %} } - override fun allocationSize(value: {{ type_name }}): ULong { + override fun allocationSize(value: {{ type_name }}): Int { {%- if e.is_flat() %} - return 4UL + return 4 {%- else %} return when(value) { {%- for variant in e.variants() %} is {{ type_name }}.{{ variant|error_variant_name }} -> ( // Add the size for the Int that specifies the variant plus the size needed for all fields - 4UL + 4 {%- for field in variant.fields() %} + {{ field|allocation_size_fn }}(value.{{ field.name()|var_name }}) {%- endfor %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ExternalTypeTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ExternalTypeTemplate.kt index b7e77f0b2de1..0fade7a0bc05 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ExternalTypeTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ExternalTypeTemplate.kt @@ -1,5 +1,5 @@ {%- let package_name=self.external_type_package_name(module_path, namespace) %} -{%- let fully_qualified_type_name = "{}.{}"|format(package_name, name|class_name(ci)) %} +{%- let fully_qualified_type_name = "{}.{}"|format(package_name, name) %} {%- let fully_qualified_ffi_converter_name = "{}.FfiConverterType{}"|format(package_name, name) %} {%- let fully_qualified_rustbuffer_name = "{}.RustBuffer"|format(package_name) %} {%- let local_rustbuffer_name = "RustBuffer{}"|format(name) %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt index 0de90b9c4b71..3b2c9d225a65 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/FfiConverterTemplate.kt @@ -20,7 +20,7 @@ public interface FfiConverter { // encoding, so we pessimistically allocate the largest size possible (3 // bytes per codepoint). Allocating extra bytes is not really a big deal // because the `RustBuffer` is short-lived. - fun allocationSize(value: KotlinType): ULong + fun allocationSize(value: KotlinType): Int // Write a Kotlin type to a `ByteBuffer` fun write(value: KotlinType, buf: ByteBuffer) @@ -34,11 +34,11 @@ public interface FfiConverter { fun lowerIntoRustBuffer(value: KotlinType): RustBuffer.ByValue { val rbuf = RustBuffer.alloc(allocationSize(value)) try { - val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity).also { + val bbuf = rbuf.data!!.getByteBuffer(0, rbuf.capacity.toLong()).also { it.order(ByteOrder.BIG_ENDIAN) } write(value, bbuf) - rbuf.writeField("len", bbuf.position().toLong()) + rbuf.writeField("len", bbuf.position()) return rbuf } catch (e: Throwable) { RustBuffer.free(rbuf) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Float32Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Float32Helper.kt index be91ac8fcb8d..eafec5d12242 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Float32Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Float32Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterFloat: FfiConverter { return value } - override fun allocationSize(value: Float) = 4UL + override fun allocationSize(value: Float) = 4 override fun write(value: Float, buf: ByteBuffer) { buf.putFloat(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Float64Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Float64Helper.kt index 5eb465f0df9e..9fc2892c955f 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Float64Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Float64Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterDouble: FfiConverter { return value } - override fun allocationSize(value: Double) = 8UL + override fun allocationSize(value: Double) = 8 override fun write(value: Double, buf: ByteBuffer) { buf.putDouble(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ForeignExecutorTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ForeignExecutorTemplate.kt new file mode 100644 index 000000000000..3544b2f9e6ec --- /dev/null +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ForeignExecutorTemplate.kt @@ -0,0 +1,83 @@ +{{ self.add_import("kotlinx.coroutines.CoroutineScope") }} +{{ self.add_import("kotlinx.coroutines.delay") }} +{{ self.add_import("kotlinx.coroutines.isActive") }} +{{ self.add_import("kotlinx.coroutines.launch") }} + +internal const val UNIFFI_RUST_TASK_CALLBACK_SUCCESS = 0.toByte() +internal const val UNIFFI_RUST_TASK_CALLBACK_CANCELLED = 1.toByte() +internal const val UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS = 0.toByte() +internal const val UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELLED = 1.toByte() +internal const val UNIFFI_FOREIGN_EXECUTOR_CALLBACK_ERROR = 2.toByte() + +// Callback function to execute a Rust task. The Kotlin code schedules these in a coroutine then +// invokes them. +internal interface UniFfiRustTaskCallback : com.sun.jna.Callback { + fun callback(rustTaskData: Pointer?, statusCode: Byte) +} + +internal object UniFfiForeignExecutorCallback : com.sun.jna.Callback { + fun callback(handle: USize, delayMs: Int, rustTask: UniFfiRustTaskCallback?, rustTaskData: Pointer?) : Byte { + if (rustTask == null) { + FfiConverterForeignExecutor.drop(handle) + return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS + } else { + val coroutineScope = FfiConverterForeignExecutor.lift(handle) + if (coroutineScope.isActive) { + val job = coroutineScope.launch { + if (delayMs > 0) { + delay(delayMs.toLong()) + } + rustTask.callback(rustTaskData, UNIFFI_RUST_TASK_CALLBACK_SUCCESS) + } + job.invokeOnCompletion { cause -> + if (cause != null) { + rustTask.callback(rustTaskData, UNIFFI_RUST_TASK_CALLBACK_CANCELLED) + } + } + return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS + } else { + return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELLED + } + } + } +} + +public object FfiConverterForeignExecutor: FfiConverter { + internal val handleMap = UniFfiHandleMap() + + internal fun drop(handle: USize) { + handleMap.remove(handle) + } + + internal fun register(lib: _UniFFILib) { + {%- match ci.ffi_foreign_executor_callback_set() %} + {%- when Some with (fn) %} + lib.{{ fn.name() }}(UniFfiForeignExecutorCallback) + {%- when None %} + {#- No foreign executor, we don't set anything #} + {% endmatch %} + } + + // Number of live handles, exposed so we can test the memory management + public fun handleCount() : Int { + return handleMap.size + } + + override fun allocationSize(value: CoroutineScope) = USize.size + + override fun lift(value: USize): CoroutineScope { + return handleMap.get(value) ?: throw RuntimeException("unknown handle in FfiConverterForeignExecutor.lift") + } + + override fun read(buf: ByteBuffer): CoroutineScope { + return lift(USize.readFromBuffer(buf)) + } + + override fun lower(value: CoroutineScope): USize { + return handleMap.insert(value) + } + + override fun write(value: CoroutineScope, buf: ByteBuffer) { + lower(value).writeToBuffer(buf) + } +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/HandleMap.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/HandleMap.kt deleted file mode 100644 index 3a5664819035..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/HandleMap.kt +++ /dev/null @@ -1,27 +0,0 @@ -// Map handles to objects -// -// This is used pass an opaque 64-bit handle representing a foreign object to the Rust code. -internal class UniffiHandleMap { - private val map = ConcurrentHashMap() - private val counter = java.util.concurrent.atomic.AtomicLong(0) - - val size: Int - get() = map.size - - // Insert a new object into the handle map and get a handle for it - fun insert(obj: T): Long { - val handle = counter.getAndAdd(1) - map.put(handle, obj) - return handle - } - - // Get an object from the handle map - fun get(handle: Long): T { - return map.get(handle) ?: throw InternalException("UniffiHandleMap.get: Invalid handle") - } - - // Remove an entry from the handlemap and get the Kotlin object back - fun remove(handle: Long): T { - return map.remove(handle) ?: throw InternalException("UniffiHandleMap: Invalid handle") - } -} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt index 1fdbd3ffc038..382a5f741364 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Helpers.kt @@ -1,43 +1,30 @@ // A handful of classes and functions to support the generated data structures. // This would be a good candidate for isolating in its own ffi-support lib. - -internal const val UNIFFI_CALL_SUCCESS = 0.toByte() -internal const val UNIFFI_CALL_ERROR = 1.toByte() -internal const val UNIFFI_CALL_UNEXPECTED_ERROR = 2.toByte() - +// Error runtime. @Structure.FieldOrder("code", "error_buf") -internal open class UniffiRustCallStatus : Structure() { +internal open class RustCallStatus : Structure() { @JvmField var code: Byte = 0 @JvmField var error_buf: RustBuffer.ByValue = RustBuffer.ByValue() - class ByValue: UniffiRustCallStatus(), Structure.ByValue + class ByValue: RustCallStatus(), Structure.ByValue fun isSuccess(): Boolean { - return code == UNIFFI_CALL_SUCCESS + return code == 0.toByte() } fun isError(): Boolean { - return code == UNIFFI_CALL_ERROR + return code == 1.toByte() } fun isPanic(): Boolean { - return code == UNIFFI_CALL_UNEXPECTED_ERROR - } - - companion object { - fun create(code: Byte, errorBuf: RustBuffer.ByValue): UniffiRustCallStatus.ByValue { - val callStatus = UniffiRustCallStatus.ByValue() - callStatus.code = code - callStatus.error_buf = errorBuf - return callStatus - } + return code == 2.toByte() } } class InternalException(message: String) : Exception(message) // Each top-level error class has a companion object that can lift the error from the call status's rust buffer -interface UniffiRustCallStatusErrorHandler { +interface CallStatusErrorHandler { fun lift(error_buf: RustBuffer.ByValue): E; } @@ -46,15 +33,15 @@ interface UniffiRustCallStatusErrorHandler { // synchronize itself // Call a rust function that returns a Result<>. Pass in the Error class companion that corresponds to the Err -private inline fun uniffiRustCallWithError(errorHandler: UniffiRustCallStatusErrorHandler, callback: (UniffiRustCallStatus) -> U): U { - var status = UniffiRustCallStatus(); +private inline fun rustCallWithError(errorHandler: CallStatusErrorHandler, callback: (RustCallStatus) -> U): U { + var status = RustCallStatus(); val return_value = callback(status) - uniffiCheckCallStatus(errorHandler, status) + checkCallStatus(errorHandler, status) return return_value } -// Check UniffiRustCallStatus and throw an error if the call wasn't successful -private fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStatusErrorHandler, status: UniffiRustCallStatus) { +// Check RustCallStatus and throw an error if the call wasn't successful +private fun checkCallStatus(errorHandler: CallStatusErrorHandler, status: RustCallStatus) { if (status.isSuccess()) { return } else if (status.isError()) { @@ -73,8 +60,8 @@ private fun uniffiCheckCallStatus(errorHandler: UniffiRustCallStat } } -// UniffiRustCallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR -object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler { +// CallStatusErrorHandler implementation for times when we don't expect a CALL_ERROR +object NullCallStatusErrorHandler: CallStatusErrorHandler { override fun lift(error_buf: RustBuffer.ByValue): InternalException { RustBuffer.free(error_buf) return InternalException("Unexpected CALL_ERROR") @@ -82,38 +69,93 @@ object UniffiNullRustCallStatusErrorHandler: UniffiRustCallStatusErrorHandler uniffiRustCall(callback: (UniffiRustCallStatus) -> U): U { - return uniffiRustCallWithError(UniffiNullRustCallStatusErrorHandler, callback); +private inline fun rustCall(callback: (RustCallStatus) -> U): U { + return rustCallWithError(NullCallStatusErrorHandler, callback); } -internal inline fun uniffiTraitInterfaceCall( - callStatus: UniffiRustCallStatus, - makeCall: () -> T, - writeReturn: (T) -> Unit, -) { - try { - writeReturn(makeCall()) - } catch(e: Exception) { - callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR - callStatus.error_buf = {{ Type::String.borrow()|lower_fn }}(e.toString()) +// IntegerType that matches Rust's `usize` / C's `size_t` +public class USize(value: Long = 0) : IntegerType(Native.SIZE_T_SIZE, value, true) { + // This is needed to fill in the gaps of IntegerType's implementation of Number for Kotlin. + override fun toByte() = toInt().toByte() + // Needed until https://youtrack.jetbrains.com/issue/KT-47902 is fixed. + @Deprecated("`toInt().toChar()` is deprecated") + override fun toChar() = toInt().toChar() + override fun toShort() = toInt().toShort() + + fun writeToBuffer(buf: ByteBuffer) { + // Make sure we always write usize integers using native byte-order, since they may be + // casted to pointer values + buf.order(ByteOrder.nativeOrder()) + try { + when (Native.SIZE_T_SIZE) { + 4 -> buf.putInt(toInt()) + 8 -> buf.putLong(toLong()) + else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") + } + } finally { + buf.order(ByteOrder.BIG_ENDIAN) + } } -} -internal inline fun uniffiTraitInterfaceCallWithError( - callStatus: UniffiRustCallStatus, - makeCall: () -> T, - writeReturn: (T) -> Unit, - lowerError: (E) -> RustBuffer.ByValue -) { - try { - writeReturn(makeCall()) - } catch(e: Exception) { - if (e is E) { - callStatus.code = UNIFFI_CALL_ERROR - callStatus.error_buf = lowerError(e) - } else { - callStatus.code = UNIFFI_CALL_UNEXPECTED_ERROR - callStatus.error_buf = {{ Type::String.borrow()|lower_fn }}(e.toString()) + companion object { + val size: Int + get() = Native.SIZE_T_SIZE + + fun readFromBuffer(buf: ByteBuffer) : USize { + // Make sure we always read usize integers using native byte-order, since they may be + // casted from pointer values + buf.order(ByteOrder.nativeOrder()) + try { + return when (Native.SIZE_T_SIZE) { + 4 -> USize(buf.getInt().toLong()) + 8 -> USize(buf.getLong()) + else -> throw RuntimeException("Invalid SIZE_T_SIZE: ${Native.SIZE_T_SIZE}") + } + } finally { + buf.order(ByteOrder.BIG_ENDIAN) + } } } } + + +// Map handles to objects +// +// This is used when the Rust code expects an opaque pointer to represent some foreign object. +// Normally we would pass a pointer to the object, but JNA doesn't support getting a pointer from an +// object reference , nor does it support leaking a reference to Rust. +// +// Instead, this class maps USize values to objects so that we can pass a pointer-sized type to +// Rust when it needs an opaque pointer. +// +// TODO: refactor callbacks to use this class +internal class UniFfiHandleMap { + private val map = ConcurrentHashMap() + // Use AtomicInteger for our counter, since we may be on a 32-bit system. 4 billion possible + // values seems like enough. If somehow we generate 4 billion handles, then this will wrap + // around back to zero and we can assume the first handle generated will have been dropped by + // then. + private val counter = java.util.concurrent.atomic.AtomicInteger(0) + + val size: Int + get() = map.size + + fun insert(obj: T): USize { + val handle = USize(counter.getAndAdd(1).toLong()) + map.put(handle, obj) + return handle + } + + fun get(handle: USize): T? { + return map.get(handle) + } + + fun remove(handle: USize): T? { + return map.remove(handle) + } +} + +// FFI type for Rust future continuations +internal interface UniFffiRustFutureContinuationCallbackType : com.sun.jna.Callback { + fun callback(continuationHandle: USize, pollResult: Short); +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int16Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int16Helper.kt index de8296fff6d6..75564276be88 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int16Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int16Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterShort: FfiConverter { return value } - override fun allocationSize(value: Short) = 2UL + override fun allocationSize(value: Short) = 2 override fun write(value: Short, buf: ByteBuffer) { buf.putShort(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int32Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int32Helper.kt index 171809a9c44e..b7a8131c8b57 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int32Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int32Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterInt: FfiConverter { return value } - override fun allocationSize(value: Int) = 4UL + override fun allocationSize(value: Int) = 4 override fun write(value: Int, buf: ByteBuffer) { buf.putInt(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int64Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int64Helper.kt index 35cf8f316906..601cfc7c2cb2 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int64Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int64Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterLong: FfiConverter { return value } - override fun allocationSize(value: Long) = 8UL + override fun allocationSize(value: Long) = 8 override fun write(value: Long, buf: ByteBuffer) { buf.putLong(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int8Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int8Helper.kt index 27c98a665965..9237768dbf84 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int8Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Int8Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterByte: FfiConverter { return value } - override fun allocationSize(value: Byte) = 1UL + override fun allocationSize(value: Byte) = 1 override fun write(value: Byte, buf: ByteBuffer) { buf.put(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Interface.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Interface.kt deleted file mode 100644 index 0b4249fb1185..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Interface.kt +++ /dev/null @@ -1,14 +0,0 @@ -{%- call kt::docstring_value(interface_docstring, 0) %} -public interface {{ interface_name }} { - {% for meth in methods.iter() -%} - {%- call kt::docstring(meth, 4) %} - {% if meth.is_async() -%}suspend {% endif -%} - fun {{ meth.name()|fn_name }}({% call kt::arg_list(meth, true) %}) - {%- match meth.return_type() -%} - {%- when Some with (return_type) %}: {{ return_type|type_name(ci) -}} - {%- else -%} - {%- endmatch %} - {% endfor %} - companion object -} - diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/MapTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/MapTemplate.kt index a80418eb003a..776c402727b1 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/MapTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/MapTemplate.kt @@ -12,8 +12,8 @@ public object {{ ffi_converter_name }}: FfiConverterRustBuffer): ULong { - val spaceForMapSize = 4UL + override fun allocationSize(value: Map<{{ key_type_name }}, {{ value_type_name }}>): Int { + val spaceForMapSize = 4 val spaceForChildren = value.map { (k, v) -> {{ key_type|allocation_size_fn }}(k) + {{ value_type|allocation_size_fn }}(v) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/NamespaceLibraryTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/NamespaceLibraryTemplate.kt index 1bac8a435c9e..6a3aeada35ed 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/NamespaceLibraryTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/NamespaceLibraryTemplate.kt @@ -13,57 +13,14 @@ private inline fun loadIndirect( return Native.load(findLibraryName(componentName), Lib::class.java) } -// Define FFI callback types -{%- for def in ci.ffi_definitions() %} -{%- match def %} -{%- when FfiDefinition::CallbackFunction(callback) %} -internal interface {{ callback.name()|ffi_callback_name }} : com.sun.jna.Callback { - fun callback( - {%- for arg in callback.arguments() -%} - {{ arg.name().borrow()|var_name }}: {{ arg.type_().borrow()|ffi_type_name_by_value }}, - {%- endfor -%} - {%- if callback.has_rust_call_status_arg() -%} - uniffiCallStatus: UniffiRustCallStatus, - {%- endif -%} - ) - {%- match callback.return_type() %} - {%- when Some(return_type) %}: {{ return_type|ffi_type_name_by_value }} - {%- when None %} - {%- endmatch %} -} -{%- when FfiDefinition::Struct(ffi_struct) %} -@Structure.FieldOrder({% for field in ffi_struct.fields() %}"{{ field.name()|var_name_raw }}"{% if !loop.last %}, {% endif %}{% endfor %}) -internal open class {{ ffi_struct.name()|ffi_struct_name }}( - {%- for field in ffi_struct.fields() %} - @JvmField internal var {{ field.name()|var_name }}: {{ field.type_().borrow()|ffi_type_name_for_ffi_struct }} = {{ field.type_()|ffi_default_value }}, - {%- endfor %} -) : Structure() { - class UniffiByValue( - {%- for field in ffi_struct.fields() %} - {{ field.name()|var_name }}: {{ field.type_().borrow()|ffi_type_name_for_ffi_struct }} = {{ field.type_()|ffi_default_value }}, - {%- endfor %} - ): {{ ffi_struct.name()|ffi_struct_name }}({%- for field in ffi_struct.fields() %}{{ field.name()|var_name }}, {%- endfor %}), Structure.ByValue - - internal fun uniffiSetValue(other: {{ ffi_struct.name()|ffi_struct_name }}) { - {%- for field in ffi_struct.fields() %} - {{ field.name()|var_name }} = other.{{ field.name()|var_name }} - {%- endfor %} - } - -} -{%- when FfiDefinition::Function(_) %} -{# functions are handled below #} -{%- endmatch %} -{%- endfor %} - // A JNA Library to expose the extern-C FFI definitions. // This is an implementation detail which will be called internally by the public API. -internal interface UniffiLib : Library { +internal interface _UniFFILib : Library { companion object { - internal val INSTANCE: UniffiLib by lazy { - loadIndirect(componentName = "{{ ci.namespace() }}") - .also { lib: UniffiLib -> + internal val INSTANCE: _UniFFILib by lazy { + loadIndirect<_UniFFILib>(componentName = "{{ ci.namespace() }}") + .also { lib: _UniFFILib -> uniffiCheckContractApiVersion(lib) uniffiCheckApiChecksums(lib) {% for fn in self.initialization_fns() -%} @@ -71,12 +28,6 @@ internal interface UniffiLib : Library { {% endfor -%} } } - {% if ci.contains_object_types() %} - // The Cleaner for the whole library - internal val CLEANER: UniffiCleaner by lazy { - UniffiCleaner.create() - } - {%- endif %} } {% for func in ci.iter_ffi_function_definitions() -%} @@ -86,7 +37,7 @@ internal interface UniffiLib : Library { {% endfor %} } -private fun uniffiCheckContractApiVersion(lib: UniffiLib) { +private fun uniffiCheckContractApiVersion(lib: _UniFFILib) { // Get the bindings contract version from our ComponentInterface val bindings_contract_version = {{ ci.uniffi_contract_version() }} // Get the scaffolding contract version by calling the into the dylib @@ -97,7 +48,7 @@ private fun uniffiCheckContractApiVersion(lib: UniffiLib) { } @Suppress("UNUSED_PARAMETER") -private fun uniffiCheckApiChecksums(lib: UniffiLib) { +private fun uniffiCheckApiChecksums(lib: _UniFFILib) { {%- for (name, expected_checksum) in ci.iter_checksums() %} if (lib.{{ name }}() != {{ expected_checksum }}.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelper.kt deleted file mode 100644 index e3e85544d724..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelper.kt +++ /dev/null @@ -1,40 +0,0 @@ - -// The cleaner interface for Object finalization code to run. -// This is the entry point to any implementation that we're using. -// -// The cleaner registers objects and returns cleanables, so now we are -// defining a `UniffiCleaner` with a `UniffiClenaer.Cleanable` to abstract the -// different implmentations available at compile time. -interface UniffiCleaner { - interface Cleanable { - fun clean() - } - - fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable - - companion object -} - -// The fallback Jna cleaner, which is available for both Android, and the JVM. -private class UniffiJnaCleaner : UniffiCleaner { - private val cleaner = com.sun.jna.internal.Cleaner.getCleaner() - - override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable = - UniffiJnaCleanable(cleaner.register(value, cleanUpTask)) -} - -private class UniffiJnaCleanable( - private val cleanable: com.sun.jna.internal.Cleaner.Cleanable, -) : UniffiCleaner.Cleanable { - override fun clean() = cleanable.clean() -} - -// We decide at uniffi binding generation time whether we were -// using Android or not. -// There are further runtime checks to chose the correct implementation -// of the cleaner. -{% if config.android_cleaner() %} -{%- include "ObjectCleanerHelperAndroid.kt" %} -{%- else %} -{%- include "ObjectCleanerHelperJvm.kt" %} -{%- endif %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperAndroid.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperAndroid.kt deleted file mode 100644 index d02587984889..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperAndroid.kt +++ /dev/null @@ -1,26 +0,0 @@ -{{- self.add_import("android.os.Build") }} -{{- self.add_import("androidx.annotation.RequiresApi") }} - -private fun UniffiCleaner.Companion.create(): UniffiCleaner = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - AndroidSystemCleaner() - } else { - UniffiJnaCleaner() - } - -// The SystemCleaner, available from API Level 33. -// Some API Level 33 OSes do not support using it, so we require API Level 34. -@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) -private class AndroidSystemCleaner : UniffiCleaner { - val cleaner = android.system.SystemCleaner.cleaner() - - override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable = - AndroidSystemCleanable(cleaner.register(value, cleanUpTask)) -} - -@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) -private class AndroidSystemCleanable( - private val cleanable: java.lang.ref.Cleaner.Cleanable, -) : UniffiCleaner.Cleanable { - override fun clean() = cleanable.clean() -} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperJvm.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperJvm.kt deleted file mode 100644 index c43bc167fca7..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectCleanerHelperJvm.kt +++ /dev/null @@ -1,25 +0,0 @@ -private fun UniffiCleaner.Companion.create(): UniffiCleaner = - try { - // For safety's sake: if the library hasn't been run in android_cleaner = true - // mode, but is being run on Android, then we still need to think about - // Android API versions. - // So we check if java.lang.ref.Cleaner is there, and use that… - java.lang.Class.forName("java.lang.ref.Cleaner") - JavaLangRefCleaner() - } catch (e: ClassNotFoundException) { - // … otherwise, fallback to the JNA cleaner. - UniffiJnaCleaner() - } - -private class JavaLangRefCleaner : UniffiCleaner { - val cleaner = java.lang.ref.Cleaner.create() - - override fun register(value: Any, cleanUpTask: Runnable): UniffiCleaner.Cleanable = - JavaLangRefCleanable(cleaner.register(value, cleanUpTask)) -} - -private class JavaLangRefCleanable( - val cleanable: java.lang.ref.Cleaner.Cleanable -) : UniffiCleaner.Cleanable { - override fun clean() = cleanable.clean() -} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectRuntime.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectRuntime.kt new file mode 100644 index 000000000000..b9352c690fa7 --- /dev/null +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectRuntime.kt @@ -0,0 +1,161 @@ +// Interface implemented by anything that can contain an object reference. +// +// Such types expose a `destroy()` method that must be called to cleanly +// dispose of the contained objects. Failure to call this method may result +// in memory leaks. +// +// The easiest way to ensure this method is called is to use the `.use` +// helper method to execute a block and destroy the object at the end. +interface Disposable { + fun destroy() + companion object { + fun destroy(vararg args: Any?) { + args.filterIsInstance() + .forEach(Disposable::destroy) + } + } +} + +inline fun T.use(block: (T) -> R) = + try { + block(this) + } finally { + try { + // N.B. our implementation is on the nullable type `Disposable?`. + this?.destroy() + } catch (e: Throwable) { + // swallow + } + } + +// The base class for all UniFFI Object types. +// +// This class provides core operations for working with the Rust `Arc` pointer to +// the live Rust struct on the other side of the FFI. +// +// There's some subtlety here, because we have to be careful not to operate on a Rust +// struct after it has been dropped, and because we must expose a public API for freeing +// the Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: +// +// * Each `FFIObject` instance holds an opaque pointer to the underlying Rust struct. +// Method calls need to read this pointer from the object's state and pass it in to +// the Rust FFI. +// +// * When an `FFIObject` is no longer needed, its pointer should be passed to a +// special destructor function provided by the Rust FFI, which will drop the +// underlying Rust struct. +// +// * Given an `FFIObject` instance, calling code is expected to call the special +// `destroy` method in order to free it after use, either by calling it explicitly +// or by using a higher-level helper like the `use` method. Failing to do so will +// leak the underlying Rust struct. +// +// * We can't assume that calling code will do the right thing, and must be prepared +// to handle Kotlin method calls executing concurrently with or even after a call to +// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. +// +// * We must never allow Rust code to operate on the underlying Rust struct after +// the destructor has been called, and must never call the destructor more than once. +// Doing so may trigger memory unsafety. +// +// If we try to implement this with mutual exclusion on access to the pointer, there is the +// possibility of a race between a method call and a concurrent call to `destroy`: +// +// * Thread A starts a method call, reads the value of the pointer, but is interrupted +// before it can pass the pointer over the FFI to Rust. +// * Thread B calls `destroy` and frees the underlying Rust struct. +// * Thread A resumes, passing the already-read pointer value to Rust and triggering +// a use-after-free. +// +// One possible solution would be to use a `ReadWriteLock`, with each method call taking +// a read lock (and thus allowed to run concurrently) and the special `destroy` method +// taking a write lock (and thus blocking on live method calls). However, we aim not to +// generate methods with any hidden blocking semantics, and a `destroy` method that might +// block if called incorrectly seems to meet that bar. +// +// So, we achieve our goals by giving each `FFIObject` an associated `AtomicLong` counter to track +// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` +// has been called. These are updated according to the following rules: +// +// * The initial value of the counter is 1, indicating a live object with no in-flight calls. +// The initial value for the flag is false. +// +// * At the start of each method call, we atomically check the counter. +// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. +// If it is nonzero them we atomically increment it by 1 and proceed with the method call. +// +// * At the end of each method call, we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// * When `destroy` is called, we atomically flip the flag from false to true. +// If the flag was already true we silently fail. +// Otherwise we atomically decrement and check the counter. +// If it has reached zero then we destroy the underlying Rust struct. +// +// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, +// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. +// +// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been +// called *and* all in-flight method calls have completed, avoiding violating any of the expectations +// of the underlying Rust code. +// +// In the future we may be able to replace some of this with automatic finalization logic, such as using +// the new "Cleaner" functionaility in Java 9. The above scheme has been designed to work even if `destroy` is +// invoked by garbage-collection machinery rather than by calling code (which by the way, it's apparently also +// possible for the JVM to finalize an object while there is an in-flight call to one of its methods [1], +// so there would still be some complexity here). +// +// Sigh...all of this for want of a robust finalization mechanism. +// +// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 +// +abstract class FFIObject( + protected val pointer: Pointer +): Disposable, AutoCloseable { + + private val wasDestroyed = AtomicBoolean(false) + private val callCounter = AtomicLong(1) + + open protected fun freeRustArcPtr() { + // To be overridden in subclasses. + } + + override fun destroy() { + // Only allow a single call to this method. + // TODO: maybe we should log a warning if called more than once? + if (this.wasDestroyed.compareAndSet(false, true)) { + // This decrement always matches the initial count of 1 given at creation time. + if (this.callCounter.decrementAndGet() == 0L) { + this.freeRustArcPtr() + } + } + } + + @Synchronized + override fun close() { + this.destroy() + } + + internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { + // Check and increment the call counter, to keep the object alive. + // This needs a compare-and-set retry loop in case of concurrent updates. + do { + val c = this.callCounter.get() + if (c == 0L) { + throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") + } + if (c == Long.MAX_VALUE) { + throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") + } + } while (! this.callCounter.compareAndSet(c, c + 1L)) + // Now we can safely do the method call without the pointer being freed concurrently. + try { + return block(this.pointer) + } finally { + // This decrement always matches the increment we performed above. + if (this.callCounter.decrementAndGet() == 0L) { + this.freeRustArcPtr() + } + } + } +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectTemplate.kt dissimilarity index 91% index 62cac7a4d012..8ce27a5d04f0 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/ObjectTemplate.kt @@ -1,295 +1,138 @@ -// This template implements a class for working with a Rust struct via a Pointer/Arc -// to the live Rust struct on the other side of the FFI. -// -// Each instance implements core operations for working with the Rust `Arc` and the -// Kotlin Pointer to work with the live Rust struct on the other side of the FFI. -// -// There's some subtlety here, because we have to be careful not to operate on a Rust -// struct after it has been dropped, and because we must expose a public API for freeing -// theq Kotlin wrapper object in lieu of reliable finalizers. The core requirements are: -// -// * Each instance holds an opaque pointer to the underlying Rust struct. -// Method calls need to read this pointer from the object's state and pass it in to -// the Rust FFI. -// -// * When an instance is no longer needed, its pointer should be passed to a -// special destructor function provided by the Rust FFI, which will drop the -// underlying Rust struct. -// -// * Given an instance, calling code is expected to call the special -// `destroy` method in order to free it after use, either by calling it explicitly -// or by using a higher-level helper like the `use` method. Failing to do so risks -// leaking the underlying Rust struct. -// -// * We can't assume that calling code will do the right thing, and must be prepared -// to handle Kotlin method calls executing concurrently with or even after a call to -// `destroy`, and to handle multiple (possibly concurrent!) calls to `destroy`. -// -// * We must never allow Rust code to operate on the underlying Rust struct after -// the destructor has been called, and must never call the destructor more than once. -// Doing so may trigger memory unsafety. -// -// * To mitigate many of the risks of leaking memory and use-after-free unsafety, a `Cleaner` -// is implemented to call the destructor when the Kotlin object becomes unreachable. -// This is done in a background thread. This is not a panacea, and client code should be aware that -// 1. the thread may starve if some there are objects that have poorly performing -// `drop` methods or do significant work in their `drop` methods. -// 2. the thread is shared across the whole library. This can be tuned by using `android_cleaner = true`, -// or `android = true` in the [`kotlin` section of the `uniffi.toml` file](https://mozilla.github.io/uniffi-rs/kotlin/configuration.html). -// -// If we try to implement this with mutual exclusion on access to the pointer, there is the -// possibility of a race between a method call and a concurrent call to `destroy`: -// -// * Thread A starts a method call, reads the value of the pointer, but is interrupted -// before it can pass the pointer over the FFI to Rust. -// * Thread B calls `destroy` and frees the underlying Rust struct. -// * Thread A resumes, passing the already-read pointer value to Rust and triggering -// a use-after-free. -// -// One possible solution would be to use a `ReadWriteLock`, with each method call taking -// a read lock (and thus allowed to run concurrently) and the special `destroy` method -// taking a write lock (and thus blocking on live method calls). However, we aim not to -// generate methods with any hidden blocking semantics, and a `destroy` method that might -// block if called incorrectly seems to meet that bar. -// -// So, we achieve our goals by giving each instance an associated `AtomicLong` counter to track -// the number of in-flight method calls, and an `AtomicBoolean` flag to indicate whether `destroy` -// has been called. These are updated according to the following rules: -// -// * The initial value of the counter is 1, indicating a live object with no in-flight calls. -// The initial value for the flag is false. -// -// * At the start of each method call, we atomically check the counter. -// If it is 0 then the underlying Rust struct has already been destroyed and the call is aborted. -// If it is nonzero them we atomically increment it by 1 and proceed with the method call. -// -// * At the end of each method call, we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// * When `destroy` is called, we atomically flip the flag from false to true. -// If the flag was already true we silently fail. -// Otherwise we atomically decrement and check the counter. -// If it has reached zero then we destroy the underlying Rust struct. -// -// Astute readers may observe that this all sounds very similar to the way that Rust's `Arc` works, -// and indeed it is, with the addition of a flag to guard against multiple calls to `destroy`. -// -// The overall effect is that the underlying Rust struct is destroyed only when `destroy` has been -// called *and* all in-flight method calls have completed, avoiding violating any of the expectations -// of the underlying Rust code. -// -// This makes a cleaner a better alternative to _not_ calling `destroy()` as -// and when the object is finished with, but the abstraction is not perfect: if the Rust object's `drop` -// method is slow, and/or there are many objects to cleanup, and it's on a low end Android device, then the cleaner -// thread may be starved, and the app will leak memory. -// -// In this case, `destroy`ing manually may be a better solution. -// -// The cleaner can live side by side with the manual calling of `destroy`. In the order of responsiveness, uniffi objects -// with Rust peers are reclaimed: -// -// 1. By calling the `destroy` method of the object, which calls `rustObject.free()`. If that doesn't happen: -// 2. When the object becomes unreachable, AND the Cleaner thread gets to call `rustObject.free()`. If the thread is starved then: -// 3. The memory is reclaimed when the process terminates. -// -// [1] https://stackoverflow.com/questions/24376768/can-java-finalize-an-object-when-it-is-still-in-scope/24380219 -// - -{{ self.add_import("java.util.concurrent.atomic.AtomicBoolean") }} -{%- if self.include_once_check("interface-support") %} - {%- include "ObjectCleanerHelper.kt" %} -{%- endif %} - -{%- let obj = ci|get_object_definition(name) %} -{%- let (interface_name, impl_class_name) = obj|object_names(ci) %} -{%- let methods = obj.methods() %} -{%- let interface_docstring = obj.docstring() %} -{%- let is_error = ci.is_name_used_as_error(name) %} -{%- let ffi_converter_name = obj|ffi_converter_name %} - -{%- include "Interface.kt" %} - -{%- call kt::docstring(obj, 0) %} -{% if (is_error) %} -open class {{ impl_class_name }} : Exception, Disposable, AutoCloseable, {{ interface_name }} { -{% else -%} -open class {{ impl_class_name }}: Disposable, AutoCloseable, {{ interface_name }} { -{%- endif %} - - constructor(pointer: Pointer) { - this.pointer = pointer - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - - /** - * This constructor can be used to instantiate a fake object. Only used for tests. Any - * attempt to actually use an object constructed this way will fail as there is no - * connected Rust object. - */ - @Suppress("UNUSED_PARAMETER") - constructor(noPointer: NoPointer) { - this.pointer = null - this.cleanable = UniffiLib.CLEANER.register(this, UniffiCleanAction(pointer)) - } - - {%- match obj.primary_constructor() %} - {%- when Some(cons) %} - {%- if cons.is_async() %} - // Note no constructor generated for this object as it is async. - {%- else %} - {%- call kt::docstring(cons, 4) %} - constructor({% call kt::arg_list(cons, true) -%}) : - this({% call kt::to_ffi_call(cons) %}) - {%- endif %} - {%- when None %} - {%- endmatch %} - - protected val pointer: Pointer? - protected val cleanable: UniffiCleaner.Cleanable - - private val wasDestroyed = AtomicBoolean(false) - private val callCounter = AtomicLong(1) - - override fun destroy() { - // Only allow a single call to this method. - // TODO: maybe we should log a warning if called more than once? - if (this.wasDestroyed.compareAndSet(false, true)) { - // This decrement always matches the initial count of 1 given at creation time. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable.clean() - } - } - } - - @Synchronized - override fun close() { - this.destroy() - } - - internal inline fun callWithPointer(block: (ptr: Pointer) -> R): R { - // Check and increment the call counter, to keep the object alive. - // This needs a compare-and-set retry loop in case of concurrent updates. - do { - val c = this.callCounter.get() - if (c == 0L) { - throw IllegalStateException("${this.javaClass.simpleName} object has already been destroyed") - } - if (c == Long.MAX_VALUE) { - throw IllegalStateException("${this.javaClass.simpleName} call counter would overflow") - } - } while (! this.callCounter.compareAndSet(c, c + 1L)) - // Now we can safely do the method call without the pointer being freed concurrently. - try { - return block(this.uniffiClonePointer()) - } finally { - // This decrement always matches the increment we performed above. - if (this.callCounter.decrementAndGet() == 0L) { - cleanable.clean() - } - } - } - - // Use a static inner class instead of a closure so as not to accidentally - // capture `this` as part of the cleanable's action. - private class UniffiCleanAction(private val pointer: Pointer?) : Runnable { - override fun run() { - pointer?.let { ptr -> - uniffiRustCall { status -> - UniffiLib.INSTANCE.{{ obj.ffi_object_free().name() }}(ptr, status) - } - } - } - } - - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.{{ obj.ffi_object_clone().name() }}(pointer!!, status) - } - } - - {% for meth in obj.methods() -%} - {%- call kt::func_decl("override", meth, 4) %} - {% endfor %} - - {%- for tm in obj.uniffi_traits() %} - {%- match tm %} - {% when UniffiTrait::Display { fmt } %} - override fun toString(): String { - return {{ fmt.return_type().unwrap()|lift_fn }}({% call kt::to_ffi_call(fmt) %}) - } - {% when UniffiTrait::Eq { eq, ne } %} - {# only equals used #} - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is {{ impl_class_name}}) return false - return {{ eq.return_type().unwrap()|lift_fn }}({% call kt::to_ffi_call(eq) %}) - } - {% when UniffiTrait::Hash { hash } %} - override fun hashCode(): Int { - return {{ hash.return_type().unwrap()|lift_fn }}({%- call kt::to_ffi_call(hash) %}).toInt() - } - {%- else %} - {%- endmatch %} - {%- endfor %} - - {# XXX - "companion object" confusion? How to have alternate constructors *and* be an error? #} - {% if !obj.alternate_constructors().is_empty() -%} - companion object { - {% for cons in obj.alternate_constructors() -%} - {% call kt::func_decl("", cons, 4) %} - {% endfor %} - } - {% else if is_error %} - companion object ErrorHandler : UniffiRustCallStatusErrorHandler<{{ impl_class_name }}> { - override fun lift(error_buf: RustBuffer.ByValue): {{ impl_class_name }} { - // Due to some mismatches in the ffi converter mechanisms, errors are a RustBuffer. - val bb = error_buf.asByteBuffer() - if (bb == null) { - throw InternalException("?") - } - return {{ ffi_converter_name }}.read(bb) - } - } - {% else %} - companion object - {% endif %} -} - -{%- if obj.has_callback_interface() %} -{%- let vtable = obj.vtable().expect("trait interface should have a vtable") %} -{%- let vtable_methods = obj.vtable_methods() %} -{%- let ffi_init_callback = obj.ffi_init_callback() %} -{% include "CallbackInterfaceImpl.kt" %} -{%- endif %} - -public object {{ ffi_converter_name }}: FfiConverter<{{ type_name }}, Pointer> { - {%- if obj.has_callback_interface() %} - internal val handleMap = UniffiHandleMap<{{ type_name }}>() - {%- endif %} - - override fun lower(value: {{ type_name }}): Pointer { - {%- if obj.has_callback_interface() %} - return Pointer(handleMap.insert(value)) - {%- else %} - return value.uniffiClonePointer() - {%- endif %} - } - - override fun lift(value: Pointer): {{ type_name }} { - return {{ impl_class_name }}(value) - } - - override fun read(buf: ByteBuffer): {{ type_name }} { - // The Rust code always writes pointers as 8 bytes, and will - // fail to compile if they don't fit. - return lift(Pointer(buf.getLong())) - } - - override fun allocationSize(value: {{ type_name }}) = 8UL - - override fun write(value: {{ type_name }}, buf: ByteBuffer) { - // The Rust code always expects pointers written as 8 bytes, - // and will fail to compile if they don't fit. - buf.putLong(Pointer.nativeValue(lower(value))) - } -} +{%- let obj = ci|get_object_definition(name) %} +{%- if self.include_once_check("ObjectRuntime.kt") %}{% include "ObjectRuntime.kt" %}{% endif %} +{{- self.add_import("java.util.concurrent.atomic.AtomicLong") }} +{{- self.add_import("java.util.concurrent.atomic.AtomicBoolean") }} + +public interface {{ type_name }}Interface { + {% for meth in obj.methods() -%} + {%- match meth.throws_type() -%} + {%- when Some with (throwable) -%} + @Throws({{ throwable|type_name(ci) }}::class) + {%- when None -%} + {%- endmatch %} + {% if meth.is_async() -%} + suspend fun {{ meth.name()|fn_name }}({% call kt::arg_list_decl(meth) %}) + {%- else -%} + fun {{ meth.name()|fn_name }}({% call kt::arg_list_decl(meth) %}) + {%- endif %} + {%- match meth.return_type() -%} + {%- when Some with (return_type) %}: {{ return_type|type_name(ci) -}} + {%- when None -%} + {%- endmatch -%} + + {% endfor %} + companion object +} + +class {{ type_name }}( + pointer: Pointer +) : FFIObject(pointer), {{ type_name }}Interface { + + {%- match obj.primary_constructor() %} + {%- when Some with (cons) %} + constructor({% call kt::arg_list_decl(cons) -%}) : + this({% call kt::to_ffi_call(cons) %}) + {%- when None %} + {%- endmatch %} + + /** + * Disconnect the object from the underlying Rust object. + * + * It can be called more than once, but once called, interacting with the object + * causes an `IllegalStateException`. + * + * Clients **must** call this method once done with the object, or cause a memory leak. + */ + override protected fun freeRustArcPtr() { + rustCall() { status -> + _UniFFILib.INSTANCE.{{ obj.ffi_object_free().name() }}(this.pointer, status) + } + } + + {% for meth in obj.methods() -%} + {%- match meth.throws_type() -%} + {%- when Some with (throwable) %} + @Throws({{ throwable|type_name(ci) }}::class) + {%- else -%} + {%- endmatch -%} + {%- if meth.is_async() %} + @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") + override suspend fun {{ meth.name()|fn_name }}({%- call kt::arg_list_decl(meth) -%}){% match meth.return_type() %}{% when Some with (return_type) %} : {{ return_type|type_name(ci) }}{% when None %}{%- endmatch %} { + return uniffiRustCallAsync( + callWithPointer { thisPtr -> + _UniFFILib.INSTANCE.{{ meth.ffi_func().name() }}( + thisPtr, + {% call kt::arg_list_lowered(meth) %} + ) + }, + {{ meth|async_poll(ci) }}, + {{ meth|async_complete(ci) }}, + {{ meth|async_free(ci) }}, + // lift function + {%- match meth.return_type() %} + {%- when Some(return_type) %} + { {{ return_type|lift_fn }}(it) }, + {%- when None %} + { Unit }, + {% endmatch %} + // Error FFI converter + {%- match meth.throws_type() %} + {%- when Some(e) %} + {{ e|type_name(ci) }}.ErrorHandler, + {%- when None %} + NullCallStatusErrorHandler, + {%- endmatch %} + ) + } + {%- else -%} + {%- match meth.return_type() -%} + {%- when Some with (return_type) -%} + override fun {{ meth.name()|fn_name }}({% call kt::arg_list_protocol(meth) %}): {{ return_type|type_name(ci) }} = + callWithPointer { + {%- call kt::to_ffi_call_with_prefix("it", meth) %} + }.let { + {{ return_type|lift_fn }}(it) + } + + {%- when None -%} + override fun {{ meth.name()|fn_name }}({% call kt::arg_list_protocol(meth) %}) = + callWithPointer { + {%- call kt::to_ffi_call_with_prefix("it", meth) %} + } + {% endmatch %} + {% endif %} + {% endfor %} + + {% if !obj.alternate_constructors().is_empty() -%} + companion object { + {% for cons in obj.alternate_constructors() -%} + fun {{ cons.name()|fn_name }}({% call kt::arg_list_decl(cons) %}): {{ type_name }} = + {{ type_name }}({% call kt::to_ffi_call(cons) %}) + {% endfor %} + } + {% else %} + companion object + {% endif %} +} + +public object {{ obj|ffi_converter_name }}: FfiConverter<{{ type_name }}, Pointer> { + override fun lower(value: {{ type_name }}): Pointer = value.callWithPointer { it } + + override fun lift(value: Pointer): {{ type_name }} { + return {{ type_name }}(value) + } + + override fun read(buf: ByteBuffer): {{ type_name }} { + // The Rust code always writes pointers as 8 bytes, and will + // fail to compile if they don't fit. + return lift(Pointer(buf.getLong())) + } + + override fun allocationSize(value: {{ type_name }}) = 8 + + override fun write(value: {{ type_name }}, buf: ByteBuffer) { + // The Rust code always expects pointers written as 8 bytes, + // and will fail to compile if they don't fit. + buf.putLong(Pointer.nativeValue(lower(value))) + } +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/OptionalTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/OptionalTemplate.kt index 98451e14518f..56cb5f87a54b 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/OptionalTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/OptionalTemplate.kt @@ -8,11 +8,11 @@ public object {{ ffi_converter_name }}: FfiConverterRustBuffer<{{ inner_type_nam return {{ inner_type|read_fn }}(buf) } - override fun allocationSize(value: {{ inner_type_name }}?): ULong { + override fun allocationSize(value: {{ inner_type_name }}?): Int { if (value == null) { - return 1UL + return 1 } else { - return 1UL + {{ inner_type|allocation_size_fn }}(value) + return 1 + {{ inner_type|allocation_size_fn }}(value) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/README.md b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/README.md deleted file mode 100644 index 0e770cb8294e..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Rules for the Kotlin template code - -## Naming - -Private variables, classes, functions, etc. should be prefixed with `uniffi`, `Uniffi`, or `UNIFFI`. -This avoids naming collisions with user-defined items. -Users will not get name collisions as long as they don't use "uniffi", which is reserved for us. - -In particular, make sure to use the `uniffi` prefix for any variable names in generated functions. -If you name a variable something like `result` the code will probably work initially. -Then it will break later on when a user decides to define a function with a parameter named `result`. - -Note: this doesn't apply to items that we want to expose, for example users may want to catch `InternalException` so doesn't get the `Uniffi` prefix. diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/RecordTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/RecordTemplate.kt index bc3028c736b6..b588ca139839 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/RecordTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/RecordTemplate.kt @@ -1,11 +1,8 @@ {%- let rec = ci|get_record_definition(name) %} -{%- if rec.has_fields() %} -{%- call kt::docstring(rec, 0) %} data class {{ type_name }} ( {%- for field in rec.fields() %} - {%- call kt::docstring(field, 4) %} - {% if config.generate_immutable_records() %}val{% else %}var{% endif %} {{ field.name()|var_name }}: {{ field|type_name(ci) -}} + var {{ field.name()|var_name }}: {{ field|type_name(ci) -}} {%- match field.default_value() %} {%- when Some with(literal) %} = {{ literal|render_literal(field, ci) }} {%- else %} @@ -21,39 +18,21 @@ data class {{ type_name }} ( {% endif %} companion object } -{%- else -%} -{%- call kt::docstring(rec, 0) %} -class {{ type_name }} { - override fun equals(other: Any?): Boolean { - return other is {{ type_name }} - } - - override fun hashCode(): Int { - return javaClass.hashCode() - } - - companion object -} -{%- endif %} public object {{ rec|ffi_converter_name }}: FfiConverterRustBuffer<{{ type_name }}> { override fun read(buf: ByteBuffer): {{ type_name }} { - {%- if rec.has_fields() %} return {{ type_name }}( {%- for field in rec.fields() %} {{ field|read_fn }}(buf), {%- endfor %} ) - {%- else %} - return {{ type_name }}() - {%- endif %} } - override fun allocationSize(value: {{ type_name }}) = {%- if rec.has_fields() %} ( + override fun allocationSize(value: {{ type_name }}) = ( {%- for field in rec.fields() %} - {{ field|allocation_size_fn }}(value.{{ field.name()|var_name }}){% if !loop.last %} +{% endif %} + {{ field|allocation_size_fn }}(value.{{ field.name()|var_name }}){% if !loop.last %} +{% endif%} {%- endfor %} - ) {%- else %} 0UL {%- endif %} + ) override fun write(value: {{ type_name }}, buf: ByteBuffer) { {%- for field in rec.fields() %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/RustBufferTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/RustBufferTemplate.kt index b28f25bfc373..dfbea240741a 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/RustBufferTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/RustBufferTemplate.kt @@ -4,41 +4,32 @@ @Structure.FieldOrder("capacity", "len", "data") open class RustBuffer : Structure() { - // Note: `capacity` and `len` are actually `ULong` values, but JVM only supports signed values. - // When dealing with these fields, make sure to call `toULong()`. - @JvmField var capacity: Long = 0 - @JvmField var len: Long = 0 + @JvmField var capacity: Int = 0 + @JvmField var len: Int = 0 @JvmField var data: Pointer? = null class ByValue: RustBuffer(), Structure.ByValue class ByReference: RustBuffer(), Structure.ByReference - internal fun setValue(other: RustBuffer) { - capacity = other.capacity - len = other.len - data = other.data - } - companion object { - internal fun alloc(size: ULong = 0UL) = uniffiRustCall() { status -> - // Note: need to convert the size to a `Long` value to make this work with JVM. - UniffiLib.INSTANCE.{{ ci.ffi_rustbuffer_alloc().name() }}(size.toLong(), status) + internal fun alloc(size: Int = 0) = rustCall() { status -> + _UniFFILib.INSTANCE.{{ ci.ffi_rustbuffer_alloc().name() }}(size, status) }.also { if(it.data == null) { throw RuntimeException("RustBuffer.alloc() returned null data pointer (size=${size})") } } - internal fun create(capacity: ULong, len: ULong, data: Pointer?): RustBuffer.ByValue { + internal fun create(capacity: Int, len: Int, data: Pointer?): RustBuffer.ByValue { var buf = RustBuffer.ByValue() - buf.capacity = capacity.toLong() - buf.len = len.toLong() + buf.capacity = capacity + buf.len = len buf.data = data return buf } - internal fun free(buf: RustBuffer.ByValue) = uniffiRustCall() { status -> - UniffiLib.INSTANCE.{{ ci.ffi_rustbuffer_free().name() }}(buf, status) + internal fun free(buf: RustBuffer.ByValue) = rustCall() { status -> + _UniFFILib.INSTANCE.{{ ci.ffi_rustbuffer_free().name() }}(buf, status) } } @@ -62,9 +53,9 @@ class RustBufferByReference : ByReference(16) { fun setValue(value: RustBuffer.ByValue) { // NOTE: The offsets are as they are in the C-like struct. val pointer = getPointer() - pointer.setLong(0, value.capacity) - pointer.setLong(8, value.len) - pointer.setPointer(16, value.data) + pointer.setInt(0, value.capacity) + pointer.setInt(4, value.len) + pointer.setPointer(8, value.data) } /** @@ -73,9 +64,9 @@ class RustBufferByReference : ByReference(16) { fun getValue(): RustBuffer.ByValue { val pointer = getPointer() val value = RustBuffer.ByValue() - value.writeField("capacity", pointer.getLong(0)) - value.writeField("len", pointer.getLong(8)) - value.writeField("data", pointer.getLong(16)) + value.writeField("capacity", pointer.getInt(0)) + value.writeField("len", pointer.getInt(4)) + value.writeField("data", pointer.getPointer(8)) return value } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/SequenceTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/SequenceTemplate.kt index 61f911cb0c3f..876d1bc05efe 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/SequenceTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/SequenceTemplate.kt @@ -8,15 +8,15 @@ public object {{ ffi_converter_name }}: FfiConverterRustBuffer): ULong { - val sizeForLength = 4UL + override fun allocationSize(value: List<{{ inner_type_name }}>): Int { + val sizeForLength = 4 val sizeForItems = value.map { {{ inner_type|allocation_size_fn }}(it) }.sum() return sizeForLength + sizeForItems } override fun write(value: List<{{ inner_type_name }}>, buf: ByteBuffer) { buf.putInt(value.size) - value.iterator().forEach { + value.forEach { {{ inner_type|write_fn }}(it, buf) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/StringHelper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/StringHelper.kt index b67435bd1ae6..68324be4f9ec 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/StringHelper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/StringHelper.kt @@ -4,7 +4,7 @@ public object FfiConverterString: FfiConverter { // store our length and avoid writing it out to the buffer. override fun lift(value: RustBuffer.ByValue): String { try { - val byteArr = ByteArray(value.len.toInt()) + val byteArr = ByteArray(value.len) value.asByteBuffer()!!.get(byteArr) return byteArr.toString(Charsets.UTF_8) } finally { @@ -31,7 +31,7 @@ public object FfiConverterString: FfiConverter { val byteBuf = toUtf8(value) // Ideally we'd pass these bytes to `ffi_bytebuffer_from_bytes`, but doing so would require us // to copy them into a JNA `Memory`. So we might as well directly copy them into a `RustBuffer`. - val rbuf = RustBuffer.alloc(byteBuf.limit().toULong()) + val rbuf = RustBuffer.alloc(byteBuf.limit()) rbuf.asByteBuffer()!!.put(byteBuf) return rbuf } @@ -39,9 +39,9 @@ public object FfiConverterString: FfiConverter { // We aren't sure exactly how many bytes our string will be once it's UTF-8 // encoded. Allocate 3 bytes per UTF-16 code unit which will always be // enough. - override fun allocationSize(value: String): ULong { - val sizeForLength = 4UL - val sizeForString = value.length.toULong() * 3UL + override fun allocationSize(value: String): Int { + val sizeForLength = 4 + val sizeForString = value.length * 3 return sizeForLength + sizeForString } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/TimestampHelper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/TimestampHelper.kt index 10a450a4bd84..21069d7ce890 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/TimestampHelper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/TimestampHelper.kt @@ -14,7 +14,7 @@ public object FfiConverterTimestamp: FfiConverterRustBuffer { } // 8 bytes for seconds, 4 bytes for nanoseconds - override fun allocationSize(value: java.time.Instant) = 12UL + override fun allocationSize(value: java.time.Instant) = 12 override fun write(value: java.time.Instant, buf: ByteBuffer) { var epochOffset = java.time.Duration.between(java.time.Instant.EPOCH, value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/TopLevelFunctionTemplate.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/TopLevelFunctionTemplate.kt dissimilarity index 100% index 681c48093a19..6a841d3484f1 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/TopLevelFunctionTemplate.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/TopLevelFunctionTemplate.kt @@ -1 +1,51 @@ -{%- call kt::func_decl("", func, 8) %} +{%- if func.is_async() %} +{%- match func.throws_type() -%} +{%- when Some with (throwable) %} +@Throws({{ throwable|type_name(ci) }}::class) +{%- else -%} +{%- endmatch %} + +@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") +suspend fun {{ func.name()|fn_name }}({%- call kt::arg_list_decl(func) -%}){% match func.return_type() %}{% when Some with (return_type) %} : {{ return_type|type_name(ci) }}{% when None %}{%- endmatch %} { + return uniffiRustCallAsync( + _UniFFILib.INSTANCE.{{ func.ffi_func().name() }}({% call kt::arg_list_lowered(func) %}), + {{ func|async_poll(ci) }}, + {{ func|async_complete(ci) }}, + {{ func|async_free(ci) }}, + // lift function + {%- match func.return_type() %} + {%- when Some(return_type) %} + { {{ return_type|lift_fn }}(it) }, + {%- when None %} + { Unit }, + {% endmatch %} + // Error FFI converter + {%- match func.throws_type() %} + {%- when Some(e) %} + {{ e|type_name(ci) }}.ErrorHandler, + {%- when None %} + NullCallStatusErrorHandler, + {%- endmatch %} + ) +} + +{%- else %} +{%- match func.throws_type() -%} +{%- when Some with (throwable) %} +@Throws({{ throwable|type_name(ci) }}::class) +{%- else -%} +{%- endmatch -%} + +{%- match func.return_type() -%} +{%- when Some with (return_type) %} + +fun {{ func.name()|fn_name }}({%- call kt::arg_list_decl(func) -%}): {{ return_type|type_name(ci) }} { + return {{ return_type|lift_fn }}({% call kt::to_ffi_call(func) %}) +} +{% when None %} + +fun {{ func.name()|fn_name }}({% call kt::arg_list_decl(func) %}) = + {% call kt::to_ffi_call(func) %} + +{% endmatch %} +{%- endif %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Types.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Types.kt index c27121b701e8..103d444ea3e5 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Types.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/Types.kt @@ -1,38 +1,5 @@ {%- import "macros.kt" as kt %} -// Interface implemented by anything that can contain an object reference. -// -// Such types expose a `destroy()` method that must be called to cleanly -// dispose of the contained objects. Failure to call this method may result -// in memory leaks. -// -// The easiest way to ensure this method is called is to use the `.use` -// helper method to execute a block and destroy the object at the end. -interface Disposable { - fun destroy() - companion object { - fun destroy(vararg args: Any?) { - args.filterIsInstance() - .forEach(Disposable::destroy) - } - } -} - -inline fun T.use(block: (T) -> R) = - try { - block(this) - } finally { - try { - // N.B. our implementation is on the nullable type `Disposable?`. - this?.destroy() - } catch (e: Throwable) { - // swallow - } - } - -/** Used to instantiate an interface without an actual pointer, for fakes in tests, mostly. */ -object NoPointer - {%- for type_ in ci.iter_types() %} {%- let type_name = type_|type_name(ci) %} {%- let ffi_converter_name = type_|ffi_converter_name %} @@ -115,6 +82,9 @@ object NoPointer {%- when Type::CallbackInterface { module_path, name } %} {% include "CallbackInterfaceTemplate.kt" %} +{%- when Type::ForeignExecutor %} +{% include "ForeignExecutorTemplate.kt" %} + {%- when Type::Timestamp %} {% include "TimestampHelper.kt" %} @@ -134,10 +104,6 @@ object NoPointer {%- if ci.has_async_fns() %} {# Import types needed for async support #} {{ self.add_import("kotlin.coroutines.resume") }} -{{ self.add_import("kotlinx.coroutines.launch") }} {{ self.add_import("kotlinx.coroutines.suspendCancellableCoroutine") }} {{ self.add_import("kotlinx.coroutines.CancellableContinuation") }} -{{ self.add_import("kotlinx.coroutines.DelicateCoroutinesApi") }} -{{ self.add_import("kotlinx.coroutines.Job") }} -{{ self.add_import("kotlinx.coroutines.GlobalScope") }} {%- endif %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt16Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt16Helper.kt index b179145b6271..279a8fa91be2 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt16Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt16Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterUShort: FfiConverter { return value.toShort() } - override fun allocationSize(value: UShort) = 2UL + override fun allocationSize(value: UShort) = 2 override fun write(value: UShort, buf: ByteBuffer) { buf.putShort(value.toShort()) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt32Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt32Helper.kt index 202d5bcd5bf7..da7b5b28d67f 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt32Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt32Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterUInt: FfiConverter { return value.toInt() } - override fun allocationSize(value: UInt) = 4UL + override fun allocationSize(value: UInt) = 4 override fun write(value: UInt, buf: ByteBuffer) { buf.putInt(value.toInt()) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt64Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt64Helper.kt index 9be2a5a69dcc..44d27ad36b12 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt64Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt64Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterULong: FfiConverter { return value.toLong() } - override fun allocationSize(value: ULong) = 8UL + override fun allocationSize(value: ULong) = 8 override fun write(value: ULong, buf: ByteBuffer) { buf.putLong(value.toLong()) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt8Helper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt8Helper.kt index ee360673e0d0..b6d176603e71 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt8Helper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/UInt8Helper.kt @@ -11,7 +11,7 @@ public object FfiConverterUByte: FfiConverter { return value.toByte() } - override fun allocationSize(value: UByte) = 1UL + override fun allocationSize(value: UByte) = 1 override fun write(value: UByte, buf: ByteBuffer) { buf.put(value.toByte()) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/macros.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/macros.kt dissimilarity index 74% index 7acfdc886125..6a95d6a66dfe 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/macros.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/macros.kt @@ -1,153 +1,77 @@ -{# -// Template to call into rust. Used in several places. -// Variable names in `arg_list` should match up with arg lists -// passed to rust via `arg_list_lowered` -#} - -{%- macro to_ffi_call(func) -%} - {%- if func.takes_self() %} - callWithPointer { - {%- call to_raw_ffi_call(func) %} - } - {% else %} - {%- call to_raw_ffi_call(func) %} - {% endif %} -{%- endmacro %} - -{%- macro to_raw_ffi_call(func) -%} - {%- match func.throws_type() %} - {%- when Some with (e) %} - uniffiRustCallWithError({{ e|type_name(ci) }}) - {%- else %} - uniffiRustCall() - {%- endmatch %} { _status -> - UniffiLib.INSTANCE.{{ func.ffi_func().name() }}( - {% if func.takes_self() %}it, {% endif -%} - {% call arg_list_lowered(func) -%} - _status) -} -{%- endmacro -%} - -{%- macro func_decl(func_decl, callable, indent) %} - {%- call docstring(callable, indent) %} - {%- match callable.throws_type() -%} - {%- when Some(throwable) %} - @Throws({{ throwable|type_name(ci) }}::class) - {%- else -%} - {%- endmatch -%} - {%- if callable.is_async() %} - @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") - {{ func_decl }} suspend fun {{ callable.name()|fn_name }}( - {%- call arg_list(callable, !callable.takes_self()) -%} - ){% match callable.return_type() %}{% when Some with (return_type) %} : {{ return_type|type_name(ci) }}{% when None %}{%- endmatch %} { - return {% call call_async(callable) %} - } - {%- else -%} - {{ func_decl }} fun {{ callable.name()|fn_name }}( - {%- call arg_list(callable, !callable.takes_self()) -%} - ){%- match callable.return_type() -%} - {%- when Some with (return_type) -%} - : {{ return_type|type_name(ci) }} { - return {{ return_type|lift_fn }}({% call to_ffi_call(callable) %}) - } - {%- when None %} - = {% call to_ffi_call(callable) %} - {%- endmatch %} - {% endif %} -{% endmacro %} - -{%- macro call_async(callable) -%} - uniffiRustCallAsync( -{%- if callable.takes_self() %} - callWithPointer { thisPtr -> - UniffiLib.INSTANCE.{{ callable.ffi_func().name() }}( - thisPtr, - {% call arg_list_lowered(callable) %} - ) - }, -{%- else %} - UniffiLib.INSTANCE.{{ callable.ffi_func().name() }}({% call arg_list_lowered(callable) %}), -{%- endif %} - {{ callable|async_poll(ci) }}, - {{ callable|async_complete(ci) }}, - {{ callable|async_free(ci) }}, - // lift function - {%- match callable.return_type() %} - {%- when Some(return_type) %} - { {{ return_type|lift_fn }}(it) }, - {%- when None %} - { Unit }, - {% endmatch %} - // Error FFI converter - {%- match callable.throws_type() %} - {%- when Some(e) %} - {{ e|type_name(ci) }}.ErrorHandler, - {%- when None %} - UniffiNullRustCallStatusErrorHandler, - {%- endmatch %} - ) -{%- endmacro %} - -{%- macro arg_list_lowered(func) %} - {%- for arg in func.arguments() %} - {{- arg|lower_fn }}({{ arg.name()|var_name }}), - {%- endfor %} -{%- endmacro -%} - -{#- -// Arglist as used in kotlin declarations of methods, functions and constructors. -// If is_decl, then default values be specified. -// Note the var_name and type_name filters. --#} - -{% macro arg_list(func, is_decl) %} -{%- for arg in func.arguments() -%} - {{ arg.name()|var_name }}: {{ arg|type_name(ci) }} -{%- if is_decl %} -{%- match arg.default_value() %} -{%- when Some with(literal) %} = {{ literal|render_literal(arg, ci) }} -{%- else %} -{%- endmatch %} -{%- endif %} -{%- if !loop.last %}, {% endif -%} -{%- endfor %} -{%- endmacro %} - -{#- -// Arglist as used in the UniffiLib function declarations. -// Note unfiltered name but ffi_type_name filters. --#} -{%- macro arg_list_ffi_decl(func) %} - {%- for arg in func.arguments() %} - {{- arg.name()|var_name }}: {{ arg.type_().borrow()|ffi_type_name_by_value -}}, - {%- endfor %} - {%- if func.has_rust_call_status_arg() %}uniffi_out_err: UniffiRustCallStatus, {% endif %} -{%- endmacro -%} - -{% macro field_name(field, field_num) %} -{%- if field.name().is_empty() -%} -v{{- field_num -}} -{%- else -%} -{{ field.name()|var_name }} -{%- endif -%} -{%- endmacro %} - -// Macro for destroying fields -{%- macro destroy_fields(member) %} - Disposable.destroy( - {%- for field in member.fields() %} - this.{{ field.name()|var_name }}{%- if !loop.last %}, {% endif -%} - {% endfor -%}) -{%- endmacro -%} - -{%- macro docstring_value(maybe_docstring, indent_spaces) %} -{%- match maybe_docstring %} -{%- when Some(docstring) %} -{{ docstring|docstring(indent_spaces) }} -{%- else %} -{%- endmatch %} -{%- endmacro %} - -{%- macro docstring(defn, indent_spaces) %} -{%- call docstring_value(defn.docstring(), indent_spaces) %} -{%- endmacro %} +{# +// Template to call into rust. Used in several places. +// Variable names in `arg_list_decl` should match up with arg lists +// passed to rust via `arg_list_lowered` +#} + +{%- macro to_ffi_call(func) -%} + {%- match func.throws_type() %} + {%- when Some with (e) %} + rustCallWithError({{ e|type_name(ci) }}) + {%- else %} + rustCall() + {%- endmatch %} { _status -> + _UniFFILib.INSTANCE.{{ func.ffi_func().name() }}({% call arg_list_lowered(func) -%} _status) +} +{%- endmacro -%} + +{%- macro to_ffi_call_with_prefix(prefix, func) %} + {%- match func.throws_type() %} + {%- when Some with (e) %} + rustCallWithError({{ e|type_name(ci) }}) + {%- else %} + rustCall() + {%- endmatch %} { _status -> + _UniFFILib.INSTANCE.{{ func.ffi_func().name() }}( + {{- prefix }}, + {% call arg_list_lowered(func) %} + _status) +} +{%- endmacro %} + +{%- macro arg_list_lowered(func) %} + {%- for arg in func.arguments() %} + {{- arg|lower_fn }}({{ arg.name()|var_name }}), + {%- endfor %} +{%- endmacro -%} + +{#- +// Arglist as used in kotlin declarations of methods, functions and constructors. +// Note the var_name and type_name filters. +-#} + +{% macro arg_list_decl(func) %} + {%- for arg in func.arguments() -%} + {{ arg.name()|var_name }}: {{ arg|type_name(ci) }} + {%- match arg.default_value() %} + {%- when Some with(literal) %} = {{ literal|render_literal(arg, ci) }} + {%- else %} + {%- endmatch %} + {%- if !loop.last %}, {% endif -%} + {%- endfor %} +{%- endmacro %} + +{% macro arg_list_protocol(func) %} + {%- for arg in func.arguments() -%} + {{ arg.name()|var_name }}: {{ arg|type_name(ci) }} + {%- if !loop.last %}, {% endif -%} + {%- endfor %} +{%- endmacro %} +{#- +// Arglist as used in the _UniFFILib function declarations. +// Note unfiltered name but ffi_type_name filters. +-#} +{%- macro arg_list_ffi_decl(func) %} + {%- for arg in func.arguments() %} + {{- arg.name()|var_name }}: {{ arg.type_().borrow()|ffi_type_name_by_value -}}, + {%- endfor %} + {%- if func.has_rust_call_status_arg() %}_uniffi_out_err: RustCallStatus, {% endif %} +{%- endmacro -%} + +// Macro for destroying fields +{%- macro destroy_fields(member) %} + Disposable.destroy( + {%- for field in member.fields() %} + this.{{ field.name()|var_name }}{%- if !loop.last %}, {% endif -%} + {% endfor -%}) +{%- endmacro -%} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/wrapper.kt b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/wrapper.kt index 2cdc72a5e2ec..9ee422901861 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/wrapper.kt +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/wrapper.kt @@ -1,8 +1,6 @@ // This file was autogenerated by some hot garbage in the `uniffi` crate. // Trust me, you don't want to mess with it! -{%- call kt::docstring_value(ci.namespace_docstring(), 0) %} - @file:Suppress("NAME_SHADOWING") package {{ config.package_name() }}; @@ -30,7 +28,6 @@ import java.nio.ByteBuffer import java.nio.ByteOrder import java.nio.CharBuffer import java.nio.charset.CodingErrorAction -import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.ConcurrentHashMap {%- for req in self.imports() %} @@ -40,7 +37,6 @@ import java.util.concurrent.ConcurrentHashMap {% include "RustBufferTemplate.kt" %} {% include "FfiConverterTemplate.kt" %} {% include "Helpers.kt" %} -{% include "HandleMap.kt" %} // Contains loading, initialization code, // and the FFI Function declarations in a com.sun.jna.Library. diff --git a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/test.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/test.rs index 082401575155..7b7854074171 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/test.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/test.rs @@ -2,8 +2,10 @@ License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use crate::bindings::TargetLanguage; -use crate::{bindings::RunScriptOptions, library_mode::generate_bindings, BindingGeneratorDefault}; +use crate::{ + bindings::{RunScriptOptions, TargetLanguage}, + library_mode::generate_bindings, +}; use anyhow::{bail, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use std::env; @@ -31,18 +33,14 @@ pub fn run_script( args: Vec, options: &RunScriptOptions, ) -> Result<()> { - let script_path = Utf8Path::new(script_file); + let script_path = Utf8Path::new(".").join(script_file); let test_helper = UniFFITestHelper::new(crate_name)?; - let out_dir = test_helper.create_out_dir(tmp_dir, script_path)?; + let out_dir = test_helper.create_out_dir(tmp_dir, &script_path)?; let cdylib_path = test_helper.copy_cdylib_to_out_dir(&out_dir)?; generate_bindings( &cdylib_path, None, - &BindingGeneratorDefault { - target_languages: vec![TargetLanguage::Kotlin], - try_format_code: false, - }, - None, + &[TargetLanguage::Kotlin], &out_dir, false, )?; diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/compounds.rs b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/compounds.rs index 16adeca9a503..b91bcbe18fc1 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/compounds.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/compounds.rs @@ -3,10 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use super::CodeType; -use crate::{ - backend::{Literal, Type}, - bindings::python::gen_python::AsCodeType, -}; +use crate::backend::{Literal, Type}; #[derive(Debug)] pub struct OptionalCodeType { @@ -36,9 +33,8 @@ impl CodeType for OptionalCodeType { fn literal(&self, literal: &Literal) -> String { match literal { - Literal::None => "None".into(), - Literal::Some { inner } => super::PythonCodeOracle.find(&self.inner).literal(inner), - _ => panic!("Invalid literal for Optional type: {literal:?}"), + Literal::Null => "None".into(), + _ => super::PythonCodeOracle.find(&self.inner).literal(literal), } } } @@ -92,11 +88,7 @@ impl MapCodeType { impl CodeType for MapCodeType { fn type_label(&self) -> String { - format!( - "dict[{}, {}]", - self.key.as_codetype().type_label(), - self.value.as_codetype().type_label() - ) + "dict".to_string() } fn canonical_name(&self) -> String { diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/executor.rs similarity index 55% copy from third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs copy to third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/executor.rs index 0a46251d6d9a..be3ba1d79184 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/executor.rs @@ -5,22 +5,14 @@ use super::CodeType; #[derive(Debug)] -pub struct ExternalCodeType { - name: String, -} - -impl ExternalCodeType { - pub fn new(name: String) -> Self { - Self { name } - } -} +pub struct ForeignExecutorCodeType; -impl CodeType for ExternalCodeType { +impl CodeType for ForeignExecutorCodeType { fn type_label(&self) -> String { - super::PythonCodeOracle.class_name(&self.name) + "asyncio.BaseEventLoop".into() } fn canonical_name(&self) -> String { - format!("Type{}", self.name) + "ForeignExecutor".into() } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs index 0a46251d6d9a..0d19c4bb3c6e 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs @@ -17,7 +17,7 @@ impl ExternalCodeType { impl CodeType for ExternalCodeType { fn type_label(&self) -> String { - super::PythonCodeOracle.class_name(&self.name) + self.name.clone() } fn canonical_name(&self) -> String { diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/mod.rs b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/mod.rs index 6a10a38e7ffa..8178fcc10298 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/mod.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/mod.rs @@ -2,9 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; use askama::Template; -use camino::Utf8Path; use heck::{ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase}; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; @@ -14,43 +13,20 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt::Debug; use crate::backend::TemplateExpression; -use crate::bindings::python; use crate::interface::*; -use crate::{BindingGenerator, BindingsConfig}; +use crate::BindingsConfig; mod callback_interface; mod compounds; mod custom; mod enum_; +mod executor; mod external; mod miscellany; mod object; mod primitives; mod record; -pub struct PythonBindingGenerator; - -impl BindingGenerator for PythonBindingGenerator { - type Config = Config; - - fn write_bindings( - &self, - ci: &ComponentInterface, - config: &Config, - out_dir: &Utf8Path, - try_format_code: bool, - ) -> Result<()> { - python::write_bindings(config, ci, out_dir, try_format_code) - } - - fn check_library_path(&self, library_path: &Utf8Path, cdylib_name: Option<&str>) -> Result<()> { - if cdylib_name.is_none() { - bail!("Generate bindings for Python requires a cdylib, but {library_path} was given"); - } - Ok(()) - } -} - /// A trait tor the implementation. trait CodeType: Debug { /// The language specific label used to reference this type. This will be used in @@ -138,8 +114,6 @@ pub struct Config { cdylib_name: Option, #[serde(default)] custom_types: HashMap, - #[serde(default)] - external_packages: HashMap, } #[derive(Debug, Clone, Default, Serialize, Deserialize)] @@ -159,16 +133,6 @@ impl Config { "uniffi".into() } } - - /// Get the package name for a given external namespace. - pub fn module_for_namespace(&self, ns: &str) -> String { - let ns = ns.to_string().to_snake_case(); - match self.external_packages.get(&ns) { - None => format!(".{ns}"), - Some(value) if value.is_empty() => ns, - Some(value) => format!("{value}.{ns}"), - } - } } impl BindingsConfig for Config { @@ -362,19 +326,7 @@ impl PythonCodeOracle { fixup_keyword(nm.to_string().to_shouty_snake_case()) } - /// Get the idiomatic Python rendering of an FFI callback function name - fn ffi_callback_name(&self, nm: &str) -> String { - format!("UNIFFI_{}", nm.to_shouty_snake_case()) - } - - /// Get the idiomatic Python rendering of an FFI struct name - fn ffi_struct_name(&self, nm: &str) -> String { - // The ctypes docs use both SHOUTY_SNAKE_CASE AND UpperCamelCase for structs. Let's use - // UpperCamelCase and reserve shouting for global variables - format!("Uniffi{}", nm.to_upper_camel_case()) - } - - fn ffi_type_label(&self, ffi_type: &FfiType) -> String { + fn ffi_type_label(ffi_type: &FfiType) -> String { match ffi_type { FfiType::Int8 => "ctypes.c_int8".to_string(), FfiType::UInt8 => "ctypes.c_uint8".to_string(), @@ -386,64 +338,19 @@ impl PythonCodeOracle { FfiType::UInt64 => "ctypes.c_uint64".to_string(), FfiType::Float32 => "ctypes.c_float".to_string(), FfiType::Float64 => "ctypes.c_double".to_string(), - FfiType::Handle => "ctypes.c_uint64".to_string(), FfiType::RustArcPtr(_) => "ctypes.c_void_p".to_string(), FfiType::RustBuffer(maybe_suffix) => match maybe_suffix { Some(suffix) => format!("_UniffiRustBuffer{suffix}"), None => "_UniffiRustBuffer".to_string(), }, - FfiType::RustCallStatus => "_UniffiRustCallStatus".to_string(), FfiType::ForeignBytes => "_UniffiForeignBytes".to_string(), - FfiType::Callback(name) => self.ffi_callback_name(name), - FfiType::Struct(name) => self.ffi_struct_name(name), + FfiType::ForeignCallback => "_UNIFFI_FOREIGN_CALLBACK_T".to_string(), // Pointer to an `asyncio.EventLoop` instance - FfiType::Reference(inner) => format!("ctypes.POINTER({})", self.ffi_type_label(inner)), - FfiType::VoidPointer => "ctypes.c_void_p".to_string(), - } - } - - /// Default values for FFI types - /// - /// Used to set a default return value when returning an error - fn ffi_default_value(&self, return_type: Option<&FfiType>) -> String { - match return_type { - Some(t) => match t { - FfiType::UInt8 - | FfiType::Int8 - | FfiType::UInt16 - | FfiType::Int16 - | FfiType::UInt32 - | FfiType::Int32 - | FfiType::UInt64 - | FfiType::Int64 => "0".to_owned(), - FfiType::Float32 | FfiType::Float64 => "0.0".to_owned(), - FfiType::RustArcPtr(_) => "ctypes.c_void_p()".to_owned(), - FfiType::RustBuffer(maybe_suffix) => match maybe_suffix { - Some(suffix) => format!("_UniffiRustBuffer{suffix}.default()"), - None => "_UniffiRustBuffer.default()".to_owned(), - }, - _ => unimplemented!("FFI return type: {t:?}"), - }, - // When we need to use a value for void returns, we use a `u8` placeholder - None => "0".to_owned(), - } - } - - /// Get the name of the protocol and class name for an object. - /// - /// If we support callback interfaces, the protocol name is the object name, and the class name is derived from that. - /// Otherwise, the class name is the object name and the protocol name is derived from that. - /// - /// This split determines what types `FfiConverter.lower()` inputs. If we support callback - /// interfaces, `lower` must lower anything that implements the protocol. If not, then lower - /// only lowers the concrete class. - fn object_names(&self, obj: &Object) -> (String, String) { - let class_name = self.class_name(obj.name()); - if obj.has_callback_interface() { - let impl_name = format!("{class_name}Impl"); - (class_name, impl_name) - } else { - (format!("{class_name}Protocol"), class_name) + FfiType::ForeignExecutorHandle => "ctypes.c_size_t".to_string(), + FfiType::ForeignExecutorCallback => "_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_T".to_string(), + FfiType::RustFutureHandle => "ctypes.c_void_p".to_string(), + FfiType::RustFutureContinuationCallback => "_UNIFFI_FUTURE_CONTINUATION_T".to_string(), + FfiType::RustFutureContinuationData => "ctypes.c_size_t".to_string(), } } } @@ -485,6 +392,7 @@ impl AsCodeType for T { Type::CallbackInterface { name, .. } => { Box::new(callback_interface::CallbackInterfaceCodeType::new(name)) } + Type::ForeignExecutor => Box::new(executor::ForeignExecutorCodeType), Type::Optional { inner_type } => { Box::new(compounds::OptionalCodeType::new(*inner_type)) } @@ -521,10 +429,6 @@ pub mod filters { Ok(format!("{}.lift", ffi_converter_name(as_ct)?)) } - pub(super) fn check_lower_fn(as_ct: &impl AsCodeType) -> Result { - Ok(format!("{}.check_lower", ffi_converter_name(as_ct)?)) - } - pub(super) fn lower_fn(as_ct: &impl AsCodeType) -> Result { Ok(format!("{}.lower", ffi_converter_name(as_ct)?)) } @@ -544,18 +448,8 @@ pub mod filters { Ok(as_ct.as_codetype().literal(literal)) } - // Get the idiomatic Python rendering of an individual enum variant's discriminant - pub fn variant_discr_literal(e: &Enum, index: &usize) -> Result { - let literal = e.variant_discr(*index).expect("invalid index"); - Ok(Type::UInt64.as_codetype().literal(&literal)) - } - pub fn ffi_type_name(type_: &FfiType) -> Result { - Ok(PythonCodeOracle.ffi_type_label(type_)) - } - - pub fn ffi_default_value(return_type: Option) -> Result { - Ok(PythonCodeOracle.ffi_default_value(return_type.as_ref())) + Ok(PythonCodeOracle::ffi_type_label(type_)) } /// Get the idiomatic Python rendering of a class name (for enums, records, errors, etc). @@ -577,51 +471,4 @@ pub mod filters { pub fn enum_variant_py(nm: &str) -> Result { Ok(PythonCodeOracle.enum_variant_name(nm)) } - - /// Get the idiomatic Python rendering of an FFI callback function name - pub fn ffi_callback_name(nm: &str) -> Result { - Ok(PythonCodeOracle.ffi_callback_name(nm)) - } - - /// Get the idiomatic Python rendering of an FFI struct name - pub fn ffi_struct_name(nm: &str) -> Result { - Ok(PythonCodeOracle.ffi_struct_name(nm)) - } - - /// Get the idiomatic Python rendering of an individual enum variant. - pub fn object_names(obj: &Object) -> Result<(String, String), askama::Error> { - Ok(PythonCodeOracle.object_names(obj)) - } - - /// Get the idiomatic Python rendering of docstring - pub fn docstring(docstring: &str, spaces: &i32) -> Result { - let docstring = textwrap::dedent(docstring); - // Escape triple quotes to avoid syntax error - let escaped = docstring.replace(r#"""""#, r#"\"\"\""#); - - let wrapped = format!("\"\"\"\n{escaped}\n\"\"\""); - - let spaces = usize::try_from(*spaces).unwrap_or_default(); - Ok(textwrap::indent(&wrapped, &" ".repeat(spaces))) - } -} - -#[cfg(test)] -mod tests { - #[test] - fn test_docstring_escape() { - let docstring = r#""""This is a docstring beginning with triple quotes. -Contains "quotes" in it. -It also has a triple quote: """ -And a even longer quote: """"""#; - - let expected = r#"""" -\"\"\"This is a docstring beginning with triple quotes. -Contains "quotes" in it. -It also has a triple quote: \"\"\" -And a even longer quote: \"\"\""" -""""#; - - assert_eq!(super::filters::docstring(docstring, &0).unwrap(), expected); - } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Async.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Async.py dissimilarity index 75% index 26daa9ba5cf8..82aa534b46ec 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Async.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Async.py @@ -1,114 +1,40 @@ -# RustFuturePoll values -_UNIFFI_RUST_FUTURE_POLL_READY = 0 -_UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1 - -# Stores futures for _uniffi_continuation_callback -_UniffiContinuationHandleMap = _UniffiHandleMap() - -UNIFFI_GLOBAL_EVENT_LOOP = None - -""" -Set the event loop to use for async functions - -This is needed if some async functions run outside of the eventloop, for example: - - A non-eventloop thread is spawned, maybe from `EventLoop.run_in_executor` or maybe from the - Rust code spawning its own thread. - - The Rust code calls an async callback method from a sync callback function, using something - like `pollster` to block on the async call. - -In this case, we need an event loop to run the Python async function, but there's no eventloop set -for the thread. Use `uniffi_set_event_loop` to force an eventloop to be used in this case. -""" -def uniffi_set_event_loop(eventloop: asyncio.BaseEventLoop): - global UNIFFI_GLOBAL_EVENT_LOOP - UNIFFI_GLOBAL_EVENT_LOOP = eventloop - -def _uniffi_get_event_loop(): - if UNIFFI_GLOBAL_EVENT_LOOP is not None: - return UNIFFI_GLOBAL_EVENT_LOOP - else: - return asyncio.get_running_loop() - -# Continuation callback for async functions -# lift the return value or error and resolve the future, causing the async function to resume. -@UNIFFI_RUST_FUTURE_CONTINUATION_CALLBACK -def _uniffi_continuation_callback(future_ptr, poll_code): - (eventloop, future) = _UniffiContinuationHandleMap.remove(future_ptr) - eventloop.call_soon_threadsafe(_uniffi_set_future_result, future, poll_code) - -def _uniffi_set_future_result(future, poll_code): - if not future.cancelled(): - future.set_result(poll_code) - -async def _uniffi_rust_call_async(rust_future, ffi_poll, ffi_complete, ffi_free, lift_func, error_ffi_converter): - try: - eventloop = _uniffi_get_event_loop() - - # Loop and poll until we see a _UNIFFI_RUST_FUTURE_POLL_READY value - while True: - future = eventloop.create_future() - ffi_poll( - rust_future, - _uniffi_continuation_callback, - _UniffiContinuationHandleMap.insert((eventloop, future)), - ) - poll_code = await future - if poll_code == _UNIFFI_RUST_FUTURE_POLL_READY: - break - - return lift_func( - _rust_call_with_error(error_ffi_converter, ffi_complete, rust_future) - ) - finally: - ffi_free(rust_future) - -{%- if ci.has_async_callback_interface_definition() %} -def uniffi_trait_interface_call_async(make_call, handle_success, handle_error): - async def make_call_and_call_callback(): - try: - handle_success(await make_call()) - except Exception as e: - print("UniFFI: Unhandled exception in trait interface call", file=sys.stderr) - traceback.print_exc(file=sys.stderr) - handle_error( - _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR, - {{ Type::String.borrow()|lower_fn }}(repr(e)), - ) - eventloop = _uniffi_get_event_loop() - task = asyncio.run_coroutine_threadsafe(make_call_and_call_callback(), eventloop) - handle = UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.insert((eventloop, task)) - return UniffiForeignFuture(handle, uniffi_foreign_future_free) - -def uniffi_trait_interface_call_async_with_error(make_call, handle_success, handle_error, error_type, lower_error): - async def make_call_and_call_callback(): - try: - try: - handle_success(await make_call()) - except error_type as e: - handle_error( - _UniffiRustCallStatus.CALL_ERROR, - lower_error(e), - ) - except Exception as e: - print("UniFFI: Unhandled exception in trait interface call", file=sys.stderr) - traceback.print_exc(file=sys.stderr) - handle_error( - _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR, - {{ Type::String.borrow()|lower_fn }}(repr(e)), - ) - eventloop = _uniffi_get_event_loop() - task = asyncio.run_coroutine_threadsafe(make_call_and_call_callback(), eventloop) - handle = UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.insert((eventloop, task)) - return UniffiForeignFuture(handle, uniffi_foreign_future_free) - -UNIFFI_FOREIGN_FUTURE_HANDLE_MAP = _UniffiHandleMap() - -@UNIFFI_FOREIGN_FUTURE_FREE -def uniffi_foreign_future_free(handle): - (eventloop, task) = UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.remove(handle) - eventloop.call_soon(uniffi_foreign_future_do_free, task) - -def uniffi_foreign_future_do_free(task): - if not task.done(): - task.cancel() -{%- endif %} +# RustFuturePoll values +_UNIFFI_RUST_FUTURE_POLL_READY = 0 +_UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1 + +# Stores futures for _uniffi_continuation_callback +_UniffiContinuationPointerManager = _UniffiPointerManager() + +# Continuation callback for async functions +# lift the return value or error and resolve the future, causing the async function to resume. +@_UNIFFI_FUTURE_CONTINUATION_T +def _uniffi_continuation_callback(future_ptr, poll_code): + (eventloop, future) = _UniffiContinuationPointerManager.release_pointer(future_ptr) + eventloop.call_soon_threadsafe(_uniffi_set_future_result, future, poll_code) + +def _uniffi_set_future_result(future, poll_code): + if not future.cancelled(): + future.set_result(poll_code) + +async def _uniffi_rust_call_async(rust_future, ffi_poll, ffi_complete, ffi_free, lift_func, error_ffi_converter): + try: + eventloop = asyncio.get_running_loop() + + # Loop and poll until we see a _UNIFFI_RUST_FUTURE_POLL_READY value + while True: + future = eventloop.create_future() + ffi_poll( + rust_future, + _UniffiContinuationPointerManager.new_pointer((eventloop, future)), + ) + poll_code = await future + if poll_code == _UNIFFI_RUST_FUTURE_POLL_READY: + break + + return lift_func( + _rust_call_with_error(error_ffi_converter, ffi_complete, rust_future) + ) + finally: + ffi_free(rust_future) + +_UniffiLib.{{ ci.ffi_rust_future_continuation_callback_set().name() }}(_uniffi_continuation_callback) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/BooleanHelper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/BooleanHelper.py index 3f8c5d1d4db6..6775e9e132e1 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/BooleanHelper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/BooleanHelper.py @@ -1,20 +1,16 @@ -class _UniffiConverterBool: +class _UniffiConverterBool(_UniffiConverterPrimitive): @classmethod - def check_lower(cls, value): + def check(cls, value): return not not value @classmethod - def lower(cls, value): - return 1 if value else 0 - - @staticmethod - def lift(value): - return value != 0 - - @classmethod def read(cls, buf): return cls.lift(buf.read_u8()) @classmethod - def write(cls, value, buf): + def write_unchecked(cls, value, buf): buf.write_u8(value) + + @staticmethod + def lift(value): + return value != 0 diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/BytesHelper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/BytesHelper.py index 4d09531322b2..196b5b29fa99 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/BytesHelper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/BytesHelper.py @@ -7,13 +7,10 @@ class _UniffiConverterBytes(_UniffiConverterRustBuffer): return buf.read(size) @staticmethod - def check_lower(value): + def write(value, buf): try: memoryview(value) except TypeError: raise TypeError("a bytes-like object is required, not {!r}".format(type(value).__name__)) - - @staticmethod - def write(value, buf): buf.write_i32(len(value)) buf.write(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceImpl.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceImpl.py deleted file mode 100644 index 676f01177a1c..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceImpl.py +++ /dev/null @@ -1,98 +0,0 @@ -{% if self.include_once_check("CallbackInterfaceRuntime.py") %}{% include "CallbackInterfaceRuntime.py" %}{% endif %} -{%- let trait_impl=format!("UniffiTraitImpl{}", name) %} - -# Put all the bits inside a class to keep the top-level namespace clean -class {{ trait_impl }}: - # For each method, generate a callback function to pass to Rust - {%- for (ffi_callback, meth) in vtable_methods.iter() %} - - @{{ ffi_callback.name()|ffi_callback_name }} - def {{ meth.name()|fn_name }}( - {%- for arg in ffi_callback.arguments() %} - {{ arg.name()|var_name }}, - {%- endfor -%} - {%- if ffi_callback.has_rust_call_status_arg() %} - uniffi_call_status_ptr, - {%- endif %} - ): - uniffi_obj = {{ ffi_converter_name }}._handle_map.get(uniffi_handle) - def make_call(): - args = ({% for arg in meth.arguments() %}{{ arg|lift_fn }}({{ arg.name()|var_name }}), {% endfor %}) - method = uniffi_obj.{{ meth.name()|fn_name }} - return method(*args) - - {% if !meth.is_async() %} - {%- match meth.return_type() %} - {%- when Some(return_type) %} - def write_return_value(v): - uniffi_out_return[0] = {{ return_type|lower_fn }}(v) - {%- when None %} - write_return_value = lambda v: None - {%- endmatch %} - - {%- match meth.throws_type() %} - {%- when None %} - _uniffi_trait_interface_call( - uniffi_call_status_ptr.contents, - make_call, - write_return_value, - ) - {%- when Some(error) %} - _uniffi_trait_interface_call_with_error( - uniffi_call_status_ptr.contents, - make_call, - write_return_value, - {{ error|type_name }}, - {{ error|lower_fn }}, - ) - {%- endmatch %} - {%- else %} - def handle_success(return_value): - uniffi_future_callback( - uniffi_callback_data, - {{ meth.foreign_future_ffi_result_struct().name()|ffi_struct_name }}( - {%- match meth.return_type() %} - {%- when Some(return_type) %} - {{ return_type|lower_fn }}(return_value), - {%- when None %} - {%- endmatch %} - _UniffiRustCallStatus.default() - ) - ) - - def handle_error(status_code, rust_buffer): - uniffi_future_callback( - uniffi_callback_data, - {{ meth.foreign_future_ffi_result_struct().name()|ffi_struct_name }}( - {%- match meth.return_type() %} - {%- when Some(return_type) %} - {{ meth.return_type().map(FfiType::from)|ffi_default_value }}, - {%- when None %} - {%- endmatch %} - _UniffiRustCallStatus(status_code, rust_buffer), - ) - ) - - {%- match meth.throws_type() %} - {%- when None %} - uniffi_out_return[0] = uniffi_trait_interface_call_async(make_call, handle_success, handle_error) - {%- when Some(error) %} - uniffi_out_return[0] = uniffi_trait_interface_call_async_with_error(make_call, handle_success, handle_error, {{ error|type_name }}, {{ error|lower_fn }}) - {%- endmatch %} - {%- endif %} - {%- endfor %} - - @{{ "CallbackInterfaceFree"|ffi_callback_name }} - def uniffi_free(uniffi_handle): - {{ ffi_converter_name }}._handle_map.remove(uniffi_handle) - - # Generate the FFI VTable. This has a field for each callback interface method. - uniffi_vtable = {{ vtable|ffi_type_name }}( - {%- for (_, meth) in vtable_methods.iter() %} - {{ meth.name()|fn_name }}, - {%- endfor %} - uniffi_free - ) - # Send Rust a pointer to the VTable. Note: this means we need to keep the struct alive forever, - # or else bad things will happen when Rust tries to access it. - _UniffiLib.{{ ffi_init_callback.name() }}(ctypes.byref(uniffi_vtable)) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceRuntime.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceRuntime.py index d802c90fdecf..0fe2ab8dc004 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceRuntime.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceRuntime.py @@ -1,3 +1,42 @@ +import threading + +class ConcurrentHandleMap: + """ + A map where inserting, getting and removing data is synchronized with a lock. + """ + + def __init__(self): + # type Handle = int + self._left_map = {} # type: Dict[Handle, Any] + self._right_map = {} # type: Dict[Any, Handle] + + self._lock = threading.Lock() + self._current_handle = 0 + self._stride = 1 + + + def insert(self, obj): + with self._lock: + if obj in self._right_map: + return self._right_map[obj] + else: + handle = self._current_handle + self._current_handle += self._stride + self._left_map[handle] = obj + self._right_map[obj] = handle + return handle + + def get(self, handle): + with self._lock: + return self._left_map.get(handle) + + def remove(self, handle): + with self._lock: + if handle in self._left_map: + obj = self._left_map.pop(handle) + del self._right_map[obj] + return obj + # Magic number for the Rust proxy to call using the same mechanism as every other method, # to free the callback once it's dropped by Rust. IDX_CALLBACK_FREE = 0 @@ -6,12 +45,22 @@ _UNIFFI_CALLBACK_SUCCESS = 0 _UNIFFI_CALLBACK_ERROR = 1 _UNIFFI_CALLBACK_UNEXPECTED_ERROR = 2 -class UniffiCallbackInterfaceFfiConverter: - _handle_map = _UniffiHandleMap() +class _UniffiConverterCallbackInterface: + _handle_map = ConcurrentHandleMap() + + def __init__(self, cb): + self._foreign_callback = cb + + def drop(self, handle): + self.__class__._handle_map.remove(handle) @classmethod def lift(cls, handle): - return cls._handle_map.get(handle) + obj = cls._handle_map.get(handle) + if not obj: + raise InternalError("The object in the handle map has been dropped already") + + return obj @classmethod def read(cls, buf): @@ -19,10 +68,6 @@ class UniffiCallbackInterfaceFfiConverter: cls.lift(handle) @classmethod - def check_lower(cls, cb): - pass - - @classmethod def lower(cls, cb): handle = cls._handle_map.insert(cb) return handle diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceTemplate.py dissimilarity index 83% index a41e58e635c9..e0e926757a7f 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceTemplate.py @@ -1,13 +1,105 @@ -{%- let cbi = ci|get_callback_interface_definition(name) %} -{%- let ffi_init_callback = cbi.ffi_init_callback() %} -{%- let protocol_name = type_name.clone() %} -{%- let protocol_docstring = cbi.docstring() %} -{%- let vtable = cbi.vtable() %} -{%- let methods = cbi.methods() %} -{%- let vtable_methods = cbi.vtable_methods() %} - -{% include "Protocol.py" %} -{% include "CallbackInterfaceImpl.py" %} - -# The _UniffiConverter which transforms the Callbacks in to Handles to pass to Rust. -{{ ffi_converter_name }} = UniffiCallbackInterfaceFfiConverter() +{%- let cbi = ci|get_callback_interface_definition(id) %} +{%- let foreign_callback = format!("foreignCallback{}", canonical_type_name) %} + +{% if self.include_once_check("CallbackInterfaceRuntime.py") %}{% include "CallbackInterfaceRuntime.py" %}{% endif %} + +# Declaration and _UniffiConverters for {{ type_name }} Callback Interface + +class {{ type_name }}: + {% for meth in cbi.methods() -%} + def {{ meth.name()|fn_name }}(self, {% call py::arg_list_decl(meth) %}): + raise NotImplementedError + + {% endfor %} + +def py_{{ foreign_callback }}(handle, method, args_data, args_len, buf_ptr): + {% for meth in cbi.methods() -%} + {% let method_name = format!("invoke_{}", meth.name())|fn_name %} + def {{ method_name }}(python_callback, args_stream, buf_ptr): + {#- Unpacking args from the _UniffiRustBuffer #} + def makeCall(): + {#- Calling the concrete callback object #} + {%- if meth.arguments().len() != 0 -%} + return python_callback.{{ meth.name()|fn_name }}( + {% for arg in meth.arguments() -%} + {{ arg|read_fn }}(args_stream) + {%- if !loop.last %}, {% endif %} + {% endfor -%} + ) + {%- else %} + return python_callback.{{ meth.name()|fn_name }}() + {%- endif %} + + def makeCallAndHandleReturn(): + {%- match meth.return_type() %} + {%- when Some(return_type) %} + rval = makeCall() + with _UniffiRustBuffer.alloc_with_builder() as builder: + {{ return_type|write_fn }}(rval, builder) + buf_ptr[0] = builder.finalize() + {%- when None %} + makeCall() + {%- endmatch %} + return _UNIFFI_CALLBACK_SUCCESS + + {%- match meth.throws_type() %} + {%- when None %} + return makeCallAndHandleReturn() + {%- when Some(err) %} + try: + return makeCallAndHandleReturn() + except {{ err|type_name }} as e: + # Catch errors declared in the UDL file + with _UniffiRustBuffer.alloc_with_builder() as builder: + {{ err|write_fn }}(e, builder) + buf_ptr[0] = builder.finalize() + return _UNIFFI_CALLBACK_ERROR + {%- endmatch %} + + {% endfor %} + + cb = {{ ffi_converter_name }}.lift(handle) + if not cb: + raise InternalError("No callback in handlemap; this is a uniffi bug") + + if method == IDX_CALLBACK_FREE: + {{ ffi_converter_name }}.drop(handle) + # Successfull return + # See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + return _UNIFFI_CALLBACK_SUCCESS + + {% for meth in cbi.methods() -%} + {% let method_name = format!("invoke_{}", meth.name())|fn_name -%} + if method == {{ loop.index }}: + # Call the method and handle any errors + # See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` for details + try: + return {{ method_name }}(cb, _UniffiRustBufferStream(args_data, args_len), buf_ptr) + except BaseException as e: + # Catch unexpected errors + try: + # Try to serialize the exception into a String + buf_ptr[0] = {{ Type::String.borrow()|lower_fn }}(repr(e)) + except: + # If that fails, just give up + pass + return _UNIFFI_CALLBACK_UNEXPECTED_ERROR + {% endfor %} + + # This should never happen, because an out of bounds method index won't + # ever be used. Once we can catch errors, we should return an InternalException. + # https://github.com/mozilla/uniffi-rs/issues/351 + + # An unexpected error happened. + # See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + return _UNIFFI_CALLBACK_UNEXPECTED_ERROR + +# We need to keep this function reference alive: +# if they get GC'd while in use then UniFFI internals could attempt to call a function +# that is in freed memory. +# That would be...uh...bad. Yeah, that's the word. Bad. +{{ foreign_callback }} = _UNIFFI_FOREIGN_CALLBACK_T(py_{{ foreign_callback }}) +_rust_call(lambda err: _UniffiLib.{{ cbi.ffi_init_callback().name() }}({{ foreign_callback }}, err)) + +# The _UniffiConverter which transforms the Callbacks in to Handles to pass to Rust. +{{ ffi_converter_name }} = _UniffiConverterCallbackInterface({{ foreign_callback }}) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CustomType.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CustomType.py index f75a85dc2756..5be6155b8499 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CustomType.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/CustomType.py @@ -18,10 +18,6 @@ class _UniffiConverterType{{ name }}: return {{ builtin|ffi_converter_name }}.lift(value) @staticmethod - def check_lower(value): - return {{ builtin|ffi_converter_name }}.check_lower(value) - - @staticmethod def lower(value): return {{ builtin|ffi_converter_name }}.lower(value) @@ -56,11 +52,6 @@ class _UniffiConverterType{{ name }}: return {{ config.into_custom.render("builtin_value") }} @staticmethod - def check_lower(value): - builtin_value = {{ config.from_custom.render("value") }} - return {{ builtin|check_lower_fn }}(builtin_value) - - @staticmethod def lower(value): builtin_value = {{ config.from_custom.render("value") }} return {{ builtin|lower_fn }}(builtin_value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/DurationHelper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/DurationHelper.py index ecb035b7f40c..10974e009db2 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/DurationHelper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/DurationHelper.py @@ -12,14 +12,10 @@ class _UniffiConverterDuration(_UniffiConverterRustBuffer): return datetime.timedelta(seconds=seconds, microseconds=microseconds) @staticmethod - def check_lower(value): - seconds = value.seconds + value.days * 24 * 3600 - if seconds < 0: - raise ValueError("Invalid duration, must be non-negative") - - @staticmethod def write(value, buf): seconds = value.seconds + value.days * 24 * 3600 nanoseconds = value.microseconds * 1000 + if seconds < 0: + raise ValueError("Invalid duration, must be non-negative") buf.write_i64(seconds) buf.write_u32(nanoseconds) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/EnumTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/EnumTemplate.py index d07dd1c44adb..84d089baf9f9 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/EnumTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/EnumTemplate.py @@ -7,59 +7,31 @@ {% if e.is_flat() %} class {{ type_name }}(enum.Enum): - {%- call py::docstring(e, 4) %} - {%- for variant in e.variants() %} - {{ variant.name()|enum_variant_py }} = {{ e|variant_discr_literal(loop.index0) }} - {%- call py::docstring(variant, 4) %} + {% for variant in e.variants() -%} + {{ variant.name()|enum_variant_py }} = {{ loop.index }} {% endfor %} {% else %} class {{ type_name }}: - {%- call py::docstring(e, 4) %} def __init__(self): raise RuntimeError("{{ type_name }} cannot be instantiated directly") # Each enum variant is a nested class of the enum itself. {% for variant in e.variants() -%} class {{ variant.name()|enum_variant_py }}: - {%- call py::docstring(variant, 8) %} - - {%- if variant.has_nameless_fields() %} - def __init__(self, *values): - if len(values) != {{ variant.fields().len() }}: - raise TypeError(f"Expected a tuple of len {{ variant.fields().len() }}, found len {len(values)}") - {%- for field in variant.fields() %} - if not isinstance(values[{{ loop.index0 }}], {{ field|type_name }}): - raise TypeError(f"unexpected type for tuple element {{ loop.index0 }} - expected '{{ field|type_name }}', got '{type(values[{{ loop.index0 }}])}'") - {%- endfor %} - self._values = values - - def __getitem__(self, index): - return self._values[index] - - def __str__(self): - return f"{{ type_name }}.{{ variant.name()|enum_variant_py }}{self._values!r}" - - def __eq__(self, other): - if not other.is_{{ variant.name()|var_name }}(): - return False - return self._values == other._values - - {%- else -%} - {%- for field in variant.fields() %} - {{ field.name()|var_name }}: "{{ field|type_name }}" - {%- call py::docstring(field, 8) %} + {% for field in variant.fields() %} + {{- field.name()|var_name }}: "{{- field|type_name }}"; {%- endfor %} @typing.no_type_check def __init__(self,{% for field in variant.fields() %}{{ field.name()|var_name }}: "{{- field|type_name }}"{% if loop.last %}{% else %}, {% endif %}{% endfor %}): - {%- if variant.has_fields() %} + {% if variant.has_fields() %} {%- for field in variant.fields() %} self.{{ field.name()|var_name }} = {{ field.name()|var_name }} {%- endfor %} - {%- else %} + {% else %} pass - {%- endif %} + {% endif %} def __str__(self): return "{{ type_name }}.{{ variant.name()|enum_variant_py }}({% for field in variant.fields() %}{{ field.name()|var_name }}={}{% if loop.last %}{% else %}, {% endif %}{% endfor %})".format({% for field in variant.fields() %}self.{{ field.name()|var_name }}{% if loop.last %}{% else %}, {% endif %}{% endfor %}) @@ -72,7 +44,6 @@ class {{ type_name }}: return False {%- endfor %} return True - {% endif %} {% endfor %} # For each variant, we have an `is_NAME` method for easily checking @@ -110,30 +81,6 @@ class {{ ffi_converter_name }}(_UniffiConverterRustBuffer): {%- endfor %} raise InternalError("Raw enum value doesn't match any cases") - @staticmethod - def check_lower(value): - {%- if e.variants().is_empty() %} - pass - {%- else %} - {%- for variant in e.variants() %} - {%- if e.is_flat() %} - if value == {{ type_name }}.{{ variant.name()|enum_variant_py }}: - {%- else %} - if value.is_{{ variant.name()|var_name }}(): - {%- endif %} - {%- for field in variant.fields() %} - {%- if variant.has_nameless_fields() %} - {{ field|check_lower_fn }}(value._values[{{ loop.index0 }}]) - {%- else %} - {{ field|check_lower_fn }}(value.{{ field.name()|var_name }}) - {%- endif %} - {%- endfor %} - return - {%- endfor %} - raise ValueError(value) - {%- endif %} - - @staticmethod def write(value, buf): {%- for variant in e.variants() %} {%- if e.is_flat() %} @@ -143,11 +90,7 @@ class {{ ffi_converter_name }}(_UniffiConverterRustBuffer): if value.is_{{ variant.name()|var_name }}(): buf.write_i32({{ loop.index }}) {%- for field in variant.fields() %} - {%- if variant.has_nameless_fields() %} - {{ field|write_fn }}(value._values[{{ loop.index0 }}], buf) - {%- else %} {{ field|write_fn }}(value.{{ field.name()|var_name }}, buf) - {%- endif %} {%- endfor %} {%- endif %} {%- endfor %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ErrorTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ErrorTemplate.py index 0911ff559a52..26a1e6452a53 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ErrorTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ErrorTemplate.py @@ -5,7 +5,6 @@ # __dict__. All of this happens in dummy class to avoid polluting the module # namespace. class {{ type_name }}(Exception): - {%- call py::docstring(e, 4) %} pass _UniffiTemp{{ type_name }} = {{ type_name }} @@ -15,14 +14,10 @@ class {{ type_name }}: # type: ignore {%- let variant_type_name = variant.name()|class_name -%} {%- if e.is_flat() %} class {{ variant_type_name }}(_UniffiTemp{{ type_name }}): - {%- call py::docstring(variant, 8) %} - def __repr__(self): return "{{ type_name }}.{{ variant_type_name }}({})".format(repr(str(self))) {%- else %} class {{ variant_type_name }}(_UniffiTemp{{ type_name }}): - {%- call py::docstring(variant, 8) %} - def __init__(self{% for field in variant.fields() %}, {{ field.name()|var_name }}{% endfor %}): {%- if variant.has_fields() %} super().__init__(", ".join([ @@ -65,20 +60,6 @@ class {{ ffi_converter_name }}(_UniffiConverterRustBuffer): raise InternalError("Raw enum value doesn't match any cases") @staticmethod - def check_lower(value): - {%- if e.variants().is_empty() %} - pass - {%- else %} - {%- for variant in e.variants() %} - if isinstance(value, {{ type_name }}.{{ variant.name()|class_name }}): - {%- for field in variant.fields() %} - {{ field|check_lower_fn }}(value.{{ field.name()|var_name }}) - {%- endfor %} - return - {%- endfor %} - {%- endif %} - - @staticmethod def write(value, buf): {%- for variant in e.variants() %} if isinstance(value, {{ type_name }}.{{ variant.name()|class_name }}): diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ExternalTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ExternalTemplate.py index 6c0cee85ef3a..71e05e8b0634 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ExternalTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ExternalTemplate.py @@ -1,9 +1,9 @@ -{%- let module = python_config.module_for_namespace(namespace) -%} +{%- let ns = namespace|fn_name %} # External type {{name}} is in namespace "{{namespace}}", crate {{module_path}} {%- let ffi_converter_name = "_UniffiConverterType{}"|format(name) %} -{{ self.add_import_of(module, ffi_converter_name) }} -{{ self.add_import_of(module, name|class_name) }} {#- import the type alias itself -#} +{{ self.add_import_of(ns, ffi_converter_name) }} +{{ self.add_import_of(ns, name) }} {#- import the type alias itself -#} {%- let rustbuffer_local_name = "_UniffiRustBuffer{}"|format(name) %} -{{ self.add_import_of_as(module, "_UniffiRustBuffer", rustbuffer_local_name) }} +{{ self.add_import_of_as(ns, "_UniffiRustBuffer", rustbuffer_local_name) }} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Float32Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Float32Helper.py index 49a1a7286efa..a52107a6381b 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Float32Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Float32Helper.py @@ -4,5 +4,5 @@ class _UniffiConverterFloat(_UniffiConverterPrimitiveFloat): return buf.read_float() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_float(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Float64Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Float64Helper.py index e2084c7b13ec..772f5080e978 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Float64Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Float64Helper.py @@ -4,5 +4,5 @@ class _UniffiConverterDouble(_UniffiConverterPrimitiveFloat): return buf.read_double() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_double(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ForeignExecutorTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ForeignExecutorTemplate.py new file mode 100644 index 000000000000..6a6932fed06f --- /dev/null +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ForeignExecutorTemplate.py @@ -0,0 +1,63 @@ +# FFI code for the ForeignExecutor type + +{{ self.add_import("asyncio") }} + +_UNIFFI_RUST_TASK_CALLBACK_SUCCESS = 0 +_UNIFFI_RUST_TASK_CALLBACK_CANCELLED = 1 +_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS = 0 +_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELED = 1 +_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_ERROR = 2 + +class {{ ffi_converter_name }}: + _pointer_manager = _UniffiPointerManager() + + @classmethod + def lower(cls, eventloop): + if not isinstance(eventloop, asyncio.BaseEventLoop): + raise TypeError("_uniffi_executor_callback: Expected EventLoop instance") + return cls._pointer_manager.new_pointer(eventloop) + + @classmethod + def write(cls, eventloop, buf): + buf.write_c_size_t(cls.lower(eventloop)) + + @classmethod + def read(cls, buf): + return cls.lift(buf.read_c_size_t()) + + @classmethod + def lift(cls, value): + return cls._pointer_manager.lookup(value) + +@_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_T +def _uniffi_executor_callback(eventloop_address, delay, task_ptr, task_data): + if task_ptr is None: + {{ ffi_converter_name }}._pointer_manager.release_pointer(eventloop_address) + return _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS + else: + eventloop = {{ ffi_converter_name }}._pointer_manager.lookup(eventloop_address) + if eventloop.is_closed(): + return _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELED + + callback = _UNIFFI_RUST_TASK(task_ptr) + # FIXME: there's no easy way to get a callback when an eventloop is closed. This means that + # if eventloop is called before the `call_soon_threadsafe()` calls are invoked, the call + # will never happen and we will probably leak a resource. + if delay == 0: + # This can be called from any thread, so make sure to use `call_soon_threadsafe' + eventloop.call_soon_threadsafe(callback, task_data, + _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS) + else: + # For delayed tasks, we use `call_soon_threadsafe()` + `call_later()` to make the + # operation threadsafe + eventloop.call_soon_threadsafe(eventloop.call_later, delay / 1000.0, callback, + task_data, _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS) + return _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS + +# Register the callback with the scaffolding +{%- match ci.ffi_foreign_executor_callback_set() %} +{%- when Some with (fn) %} +_UniffiLib.{{ fn.name() }}(_uniffi_executor_callback) +{%- when None %} +{#- No foreign executor, we don't set anything #} +{% endmatch %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/HandleMap.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/HandleMap.py deleted file mode 100644 index f7c13cf74553..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/HandleMap.py +++ /dev/null @@ -1,33 +0,0 @@ -class _UniffiHandleMap: - """ - A map where inserting, getting and removing data is synchronized with a lock. - """ - - def __init__(self): - # type Handle = int - self._map = {} # type: Dict[Handle, Any] - self._lock = threading.Lock() - self._counter = itertools.count() - - def insert(self, obj): - with self._lock: - handle = next(self._counter) - self._map[handle] = obj - return handle - - def get(self, handle): - try: - with self._lock: - return self._map[handle] - except KeyError: - raise InternalError("UniffiHandleMap.get: Invalid handle") - - def remove(self, handle): - try: - with self._lock: - return self._map.pop(handle) - except KeyError: - raise InternalError("UniffiHandleMap.remove: Invalid handle") - - def __len__(self): - return len(self._map) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Helpers.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Helpers.py index 5d4bcbba8997..dca962f176c3 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Helpers.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Helpers.py @@ -16,19 +16,15 @@ class _UniffiRustCallStatus(ctypes.Structure): # These match the values from the uniffi::rustcalls module CALL_SUCCESS = 0 CALL_ERROR = 1 - CALL_UNEXPECTED_ERROR = 2 - - @staticmethod - def default(): - return _UniffiRustCallStatus(code=_UniffiRustCallStatus.CALL_SUCCESS, error_buf=_UniffiRustBuffer.default()) + CALL_PANIC = 2 def __str__(self): if self.code == _UniffiRustCallStatus.CALL_SUCCESS: return "_UniffiRustCallStatus(CALL_SUCCESS)" elif self.code == _UniffiRustCallStatus.CALL_ERROR: return "_UniffiRustCallStatus(CALL_ERROR)" - elif self.code == _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR: - return "_UniffiRustCallStatus(CALL_UNEXPECTED_ERROR)" + elif self.code == _UniffiRustCallStatus.CALL_PANIC: + return "_UniffiRustCallStatus(CALL_PANIC)" else: return "_UniffiRustCallStatus()" @@ -41,7 +37,7 @@ def _rust_call_with_error(error_ffi_converter, fn, *args): # # This function is used for rust calls that return Result<> and therefore can set the CALL_ERROR status code. # error_ffi_converter must be set to the _UniffiConverter for the error class that corresponds to the result. - call_status = _UniffiRustCallStatus.default() + call_status = _UniffiRustCallStatus(code=_UniffiRustCallStatus.CALL_SUCCESS, error_buf=_UniffiRustBuffer(0, 0, None)) args_with_error = args + (ctypes.byref(call_status),) result = fn(*args_with_error) @@ -57,7 +53,7 @@ def _uniffi_check_call_status(error_ffi_converter, call_status): raise InternalError("_rust_call_with_error: CALL_ERROR, but error_ffi_converter is None") else: raise error_ffi_converter.lift(call_status.error_buf) - elif call_status.code == _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR: + elif call_status.code == _UniffiRustCallStatus.CALL_PANIC: # When the rust code sees a panic, it tries to construct a _UniffiRustBuffer # with the message. But if that code panics, then it just sends back # an empty buffer. @@ -70,20 +66,10 @@ def _uniffi_check_call_status(error_ffi_converter, call_status): raise InternalError("Invalid _UniffiRustCallStatus code: {}".format( call_status.code)) -def _uniffi_trait_interface_call(call_status, make_call, write_return_value): - try: - return write_return_value(make_call()) - except Exception as e: - call_status.code = _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR - call_status.error_buf = {{ Type::String.borrow()|lower_fn }}(repr(e)) +# A function pointer for a callback as defined by UniFFI. +# Rust definition `fn(handle: u64, method: u32, args: _UniffiRustBuffer, buf_ptr: *mut _UniffiRustBuffer) -> int` +_UNIFFI_FOREIGN_CALLBACK_T = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_ulonglong, ctypes.c_ulong, ctypes.POINTER(ctypes.c_char), ctypes.c_int, ctypes.POINTER(_UniffiRustBuffer)) + +# UniFFI future continuation +_UNIFFI_FUTURE_CONTINUATION_T = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_int8) -def _uniffi_trait_interface_call_with_error(call_status, make_call, write_return_value, error_type, lower_error): - try: - try: - return write_return_value(make_call()) - except error_type as e: - call_status.code = _UniffiRustCallStatus.CALL_ERROR - call_status.error_buf = lower_error(e) - except Exception as e: - call_status.code = _UniffiRustCallStatus.CALL_UNEXPECTED_ERROR - call_status.error_buf = {{ Type::String.borrow()|lower_fn }}(repr(e)) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int16Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int16Helper.py index befa5633846d..99f19dc1c006 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int16Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int16Helper.py @@ -8,5 +8,5 @@ class _UniffiConverterInt16(_UniffiConverterPrimitiveInt): return buf.read_i16() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_i16(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int32Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int32Helper.py index 70644f671714..3b142c8749e7 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int32Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int32Helper.py @@ -8,5 +8,5 @@ class _UniffiConverterInt32(_UniffiConverterPrimitiveInt): return buf.read_i32() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_i32(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int64Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int64Helper.py index 232f127bd6ed..6e94379cbf93 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int64Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int64Helper.py @@ -8,5 +8,5 @@ class _UniffiConverterInt64(_UniffiConverterPrimitiveInt): return buf.read_i64() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_i64(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int8Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int8Helper.py index c1de1625e73d..732530e3cb18 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int8Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Int8Helper.py @@ -8,5 +8,5 @@ class _UniffiConverterInt8(_UniffiConverterPrimitiveInt): return buf.read_i8() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_i8(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/MapTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/MapTemplate.py index a09ca28a30aa..387227ed098e 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/MapTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/MapTemplate.py @@ -3,12 +3,6 @@ class {{ ffi_converter_name }}(_UniffiConverterRustBuffer): @classmethod - def check_lower(cls, items): - for (key, value) in items.items(): - {{ key_ffi_converter }}.check_lower(key) - {{ value_ffi_converter }}.check_lower(value) - - @classmethod def write(cls, items, buf): buf.write_i32(len(items)) for (key, value) in items.items(): diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/NamespaceLibraryTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/NamespaceLibraryTemplate.py index 1929f9aad6fe..fac6cd556438 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/NamespaceLibraryTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/NamespaceLibraryTemplate.py @@ -1,6 +1,22 @@ # Define some ctypes FFI types that we use in the library """ +ctypes type for the foreign executor callback. This is a built-in interface for scheduling +tasks + +Args: + executor: opaque c_size_t value representing the eventloop + delay: delay in ms + task: function pointer to the task callback + task_data: void pointer to the task callback data + +Normally we should call task(task_data) after the detail. +However, when task is NULL this indicates that Rust has dropped the ForeignExecutor and we should +decrease the EventLoop refcount. +""" +_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_T = ctypes.CFUNCTYPE(ctypes.c_int8, ctypes.c_size_t, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p) + +""" Function pointer for a Rust task, which a callback function that takes a opaque pointer """ _UNIFFI_RUST_TASK = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_int8) @@ -9,7 +25,7 @@ def _uniffi_future_callback_t(return_type): """ Factory function to create callback function types for async functions """ - return ctypes.CFUNCTYPE(None, ctypes.c_uint64, return_type, _UniffiRustCallStatus) + return ctypes.CFUNCTYPE(None, ctypes.c_size_t, return_type, _UniffiRustCallStatus) def _uniffi_load_indirect(): """ @@ -56,37 +72,12 @@ def _uniffi_check_api_checksums(lib): # This is an implementation detail which will be called internally by the public API. _UniffiLib = _uniffi_load_indirect() - -{%- for def in ci.ffi_definitions() %} -{%- match def %} -{%- when FfiDefinition::CallbackFunction(callback) %} -{{ callback.name()|ffi_callback_name }} = ctypes.CFUNCTYPE( - {%- match callback.return_type() %} - {%- when Some(return_type) %}{{ return_type|ffi_type_name }}, - {%- when None %}None, - {%- endmatch %} - {%- for arg in callback.arguments() -%} - {{ arg.type_().borrow()|ffi_type_name }}, - {%- endfor -%} - {%- if callback.has_rust_call_status_arg() %} - ctypes.POINTER(_UniffiRustCallStatus), - {%- endif %} -) -{%- when FfiDefinition::Struct(ffi_struct) %} -class {{ ffi_struct.name()|ffi_struct_name }}(ctypes.Structure): - _fields_ = [ - {%- for field in ffi_struct.fields() %} - ("{{ field.name()|var_name }}", {{ field.type_().borrow()|ffi_type_name }}), - {%- endfor %} - ] -{%- when FfiDefinition::Function(func) %} +{%- for func in ci.iter_ffi_function_definitions() %} _UniffiLib.{{ func.name() }}.argtypes = ( {%- call py::arg_list_ffi_decl(func) -%} ) _UniffiLib.{{ func.name() }}.restype = {% match func.return_type() %}{% when Some with (type_) %}{{ type_|ffi_type_name }}{% when None %}None{% endmatch %} -{%- endmatch %} {%- endfor %} - {# Ensure to call the contract verification only after we defined all functions. -#} _uniffi_check_contract_api_version(_UniffiLib) _uniffi_check_api_checksums(_UniffiLib) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ObjectTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ObjectTemplate.py index 18dca4743ade..7e98f7c46f65 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ObjectTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ObjectTemplate.py @@ -1,33 +1,14 @@ {%- let obj = ci|get_object_definition(name) %} -{%- let (protocol_name, impl_name) = obj|object_names %} -{%- let methods = obj.methods() %} -{%- let protocol_docstring = obj.docstring() %} - -{% include "Protocol.py" %} - -{% if ci.is_name_used_as_error(name) %} -class {{ impl_name }}(Exception): -{%- else %} -class {{ impl_name }}: -{%- endif %} - {%- call py::docstring(obj, 4) %} + +class {{ type_name }}: _pointer: ctypes.c_void_p {%- match obj.primary_constructor() %} {%- when Some with (cons) %} -{%- if cons.is_async() %} - def __init__(self, *args, **kw): - raise ValueError("async constructors not supported.") -{%- else %} def __init__(self, {% call py::arg_list_decl(cons) -%}): - {%- call py::docstring(cons, 8) %} {%- call py::setup_args_extra_indent(cons) %} self._pointer = {% call py::to_ffi_call(cons) %} -{%- endif %} {%- when None %} - {# no __init__ means simple construction without a pointer works, which can confuse #} - def __init__(self, *args, **kwargs): - raise ValueError("This class has no default constructor") {%- endmatch %} def __del__(self): @@ -36,9 +17,6 @@ class {{ impl_name }}: if pointer is not None: _rust_call(_UniffiLib.{{ obj.ffi_object_free().name() }}, pointer) - def _uniffi_clone_pointer(self): - return _rust_call(_UniffiLib.{{ obj.ffi_object_clone().name() }}, self._pointer) - # Used by alternative constructors or any methods which return this type. @classmethod def _make_instance_(cls, pointer): @@ -51,32 +29,17 @@ class {{ impl_name }}: {%- for cons in obj.alternate_constructors() %} @classmethod -{%- if cons.is_async() %} - async def {{ cons.name()|fn_name }}(cls, {% call py::arg_list_decl(cons) %}): - {%- call py::docstring(cons, 8) %} - {%- call py::setup_args_extra_indent(cons) %} - - return await _uniffi_rust_call_async( - _UniffiLib.{{ cons.ffi_func().name() }}({% call py::arg_list_lowered(cons) %}), - _UniffiLib.{{ cons.ffi_rust_future_poll(ci) }}, - _UniffiLib.{{ cons.ffi_rust_future_complete(ci) }}, - _UniffiLib.{{ cons.ffi_rust_future_free(ci) }}, - {{ ffi_converter_name }}.lift, - {% call py::error_ffi_converter(cons) %} - ) -{%- else %} def {{ cons.name()|fn_name }}(cls, {% call py::arg_list_decl(cons) %}): - {%- call py::docstring(cons, 8) %} {%- call py::setup_args_extra_indent(cons) %} # Call the (fallible) function before creating any half-baked object instances. pointer = {% call py::to_ffi_call(cons) %} return cls._make_instance_(pointer) -{%- endif %} {% endfor %} {%- for meth in obj.methods() -%} {%- call py::method_decl(meth.name()|fn_name, meth) %} -{%- endfor %} +{% endfor %} + {%- for tm in obj.uniffi_traits() -%} {%- match tm %} {%- when UniffiTrait::Debug { fmt } %} @@ -88,84 +51,37 @@ class {{ impl_name }}: if not isinstance(other, {{ type_name }}): return NotImplemented - return {{ eq.return_type().unwrap()|lift_fn }}({% call py::to_ffi_call_with_prefix("self._uniffi_clone_pointer()", eq) %}) + return {{ eq.return_type().unwrap()|lift_fn }}({% call py::to_ffi_call_with_prefix("self._pointer", eq) %}) def __ne__(self, other: object) -> {{ ne.return_type().unwrap()|type_name }}: if not isinstance(other, {{ type_name }}): return NotImplemented - return {{ ne.return_type().unwrap()|lift_fn }}({% call py::to_ffi_call_with_prefix("self._uniffi_clone_pointer()", ne) %}) + return {{ ne.return_type().unwrap()|lift_fn }}({% call py::to_ffi_call_with_prefix("self._pointer", ne) %}) {%- when UniffiTrait::Hash { hash } %} {%- call py::method_decl("__hash__", hash) %} -{%- endmatch %} -{%- endfor %} - -{%- if obj.has_callback_interface() %} -{%- let ffi_init_callback = obj.ffi_init_callback() %} -{%- let vtable = obj.vtable().expect("trait interface should have a vtable") %} -{%- let vtable_methods = obj.vtable_methods() %} -{% include "CallbackInterfaceImpl.py" %} -{%- endif %} - -{# Objects as error #} -{%- if ci.is_name_used_as_error(name) %} -{# Due to some mismatches in the ffi converter mechanisms, errors are forced to be a RustBuffer #} -class {{ ffi_converter_name }}__as_error(_UniffiConverterRustBuffer): - @classmethod - def read(cls, buf): - raise NotImplementedError() - - @classmethod - def write(cls, value, buf): - raise NotImplementedError() - - @staticmethod - def lift(value): - # Errors are always a rust buffer holding a pointer - which is a "read" - with value.consume_with_stream() as stream: - return {{ ffi_converter_name }}.read(stream) - - @staticmethod - def lower(value): - raise NotImplementedError() +{% endmatch %} +{% endfor %} -{%- endif %} class {{ ffi_converter_name }}: - {%- if obj.has_callback_interface() %} - _handle_map = _UniffiHandleMap() - {%- endif %} - - @staticmethod - def lift(value: int): - return {{ impl_name }}._make_instance_(value) - - @staticmethod - def check_lower(value: {{ type_name }}): - {%- if obj.has_callback_interface() %} - pass - {%- else %} - if not isinstance(value, {{ impl_name }}): - raise TypeError("Expected {{ impl_name }} instance, {} found".format(type(value).__name__)) - {%- endif %} - - @staticmethod - def lower(value: {{ protocol_name }}): - {%- if obj.has_callback_interface() %} - return {{ ffi_converter_name }}._handle_map.insert(value) - {%- else %} - if not isinstance(value, {{ impl_name }}): - raise TypeError("Expected {{ impl_name }} instance, {} found".format(type(value).__name__)) - return value._uniffi_clone_pointer() - {%- endif %} - @classmethod - def read(cls, buf: _UniffiRustBuffer): + def read(cls, buf): ptr = buf.read_u64() if ptr == 0: raise InternalError("Raw pointer value was null") return cls.lift(ptr) @classmethod - def write(cls, value: {{ protocol_name }}, buf: _UniffiRustBuffer): + def write(cls, value, buf): + if not isinstance(value, {{ type_name }}): + raise TypeError("Expected {{ type_name }} instance, {} found".format(type(value).__name__)) buf.write_u64(cls.lower(value)) + + @staticmethod + def lift(value): + return {{ type_name }}._make_instance_(value) + + @staticmethod + def lower(value): + return value._pointer diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/OptionalTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/OptionalTemplate.py index 4c07ae3e346f..e406c51d4928 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/OptionalTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/OptionalTemplate.py @@ -2,11 +2,6 @@ class {{ ffi_converter_name }}(_UniffiConverterRustBuffer): @classmethod - def check_lower(cls, value): - if value is not None: - {{ inner_ffi_converter }}.check_lower(value) - - @classmethod def write(cls, value, buf): if value is None: buf.write_u8(0) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/PointerManager.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/PointerManager.py new file mode 100644 index 000000000000..23aa28eab44c --- /dev/null +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/PointerManager.py @@ -0,0 +1,68 @@ +class _UniffiPointerManagerCPython: + """ + Manage giving out pointers to Python objects on CPython + + This class is used to generate opaque pointers that reference Python objects to pass to Rust. + It assumes a CPython platform. See _UniffiPointerManagerGeneral for the alternative. + """ + + def new_pointer(self, obj): + """ + Get a pointer for an object as a ctypes.c_size_t instance + + Each call to new_pointer() must be balanced with exactly one call to release_pointer() + + This returns a ctypes.c_size_t. This is always the same size as a pointer and can be + interchanged with pointers for FFI function arguments and return values. + """ + # IncRef the object since we're going to pass a pointer to Rust + ctypes.pythonapi.Py_IncRef(ctypes.py_object(obj)) + # id() is the object address on CPython + # (https://docs.python.org/3/library/functions.html#id) + return id(obj) + + def release_pointer(self, address): + py_obj = ctypes.cast(address, ctypes.py_object) + obj = py_obj.value + ctypes.pythonapi.Py_DecRef(py_obj) + return obj + + def lookup(self, address): + return ctypes.cast(address, ctypes.py_object).value + +class _UniffiPointerManagerGeneral: + """ + Manage giving out pointers to Python objects on non-CPython platforms + + This has the same API as _UniffiPointerManagerCPython, but doesn't assume we're running on + CPython and is slightly slower. + + Instead of using real pointers, it maps integer values to objects and returns the keys as + c_size_t values. + """ + + def __init__(self): + self._map = {} + self._lock = threading.Lock() + self._current_handle = 0 + + def new_pointer(self, obj): + with self._lock: + handle = self._current_handle + self._current_handle += 1 + self._map[handle] = obj + return handle + + def release_pointer(self, handle): + with self._lock: + return self._map.pop(handle) + + def lookup(self, handle): + with self._lock: + return self._map[handle] + +# Pick an pointer manager implementation based on the platform +if platform.python_implementation() == 'CPython': + _UniffiPointerManager = _UniffiPointerManagerCPython # type: ignore +else: + _UniffiPointerManager = _UniffiPointerManagerGeneral # type: ignore diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Protocol.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Protocol.py deleted file mode 100644 index 3b7e93596aca..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Protocol.py +++ /dev/null @@ -1,9 +0,0 @@ -class {{ protocol_name }}(typing.Protocol): - {%- call py::docstring_value(protocol_docstring, 4) %} - {%- for meth in methods.iter() %} - def {{ meth.name()|fn_name }}(self, {% call py::arg_list_decl(meth) %}): - {%- call py::docstring(meth, 8) %} - raise NotImplementedError - {%- else %} - pass - {%- endfor %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RecordTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RecordTemplate.py index 0b5634eb526e..99a30e120fef 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RecordTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RecordTemplate.py @@ -1,14 +1,11 @@ {%- let rec = ci|get_record_definition(name) %} class {{ type_name }}: - {%- call py::docstring(rec, 4) %} - {%- for field in rec.fields() %} - {{ field.name()|var_name }}: "{{ field|type_name }}" - {%- call py::docstring(field, 4) %} + {% for field in rec.fields() %} + {{- field.name()|var_name }}: "{{- field|type_name }}"; {%- endfor %} - {%- if rec.has_fields() %} @typing.no_type_check - def __init__(self, *, {% for field in rec.fields() %} + def __init__(self, {% for field in rec.fields() %} {{- field.name()|var_name }}: "{{- field|type_name }}" {%- if field.default_value().is_some() %} = _DEFAULT{% endif %} {%- if !loop.last %}, {% endif %} @@ -25,7 +22,6 @@ class {{ type_name }}: self.{{ field_name }} = {{ field_name }} {%- endmatch %} {%- endfor %} - {%- endif %} def __str__(self): return "{{ type_name }}({% for field in rec.fields() %}{{ field.name()|var_name }}={}{% if loop.last %}{% else %}, {% endif %}{% endfor %})".format({% for field in rec.fields() %}self.{{ field.name()|var_name }}{% if loop.last %}{% else %}, {% endif %}{% endfor %}) @@ -47,21 +43,7 @@ class {{ ffi_converter_name }}(_UniffiConverterRustBuffer): ) @staticmethod - def check_lower(value): - {%- if rec.fields().is_empty() %} - pass - {%- else %} - {%- for field in rec.fields() %} - {{ field|check_lower_fn }}(value.{{ field.name()|var_name }}) - {%- endfor %} - {%- endif %} - - @staticmethod def write(value, buf): - {%- if rec.has_fields() %} {%- for field in rec.fields() %} {{ field|write_fn }}(value.{{ field.name()|var_name }}, buf) {%- endfor %} - {%- else %} - pass - {%- endif %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RustBufferHelper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RustBufferHelper.py index 4db74fb15717..daabd5b4b9b3 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RustBufferHelper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RustBufferHelper.py @@ -1,16 +1,28 @@ # Types conforming to `_UniffiConverterPrimitive` pass themselves directly over the FFI. class _UniffiConverterPrimitive: @classmethod + def check(cls, value): + return value + + @classmethod def lift(cls, value): return value @classmethod def lower(cls, value): + return cls.lowerUnchecked(cls.check(value)) + + @classmethod + def lowerUnchecked(cls, value): return value + @classmethod + def write(cls, value, buf): + cls.write_unchecked(cls.check(value), buf) + class _UniffiConverterPrimitiveInt(_UniffiConverterPrimitive): @classmethod - def check_lower(cls, value): + def check(cls, value): try: value = value.__index__() except Exception: @@ -19,16 +31,18 @@ class _UniffiConverterPrimitiveInt(_UniffiConverterPrimitive): raise TypeError("__index__ returned non-int (type {})".format(type(value).__name__)) if not cls.VALUE_MIN <= value < cls.VALUE_MAX: raise ValueError("{} requires {} <= value < {}".format(cls.CLASS_NAME, cls.VALUE_MIN, cls.VALUE_MAX)) + return super().check(value) class _UniffiConverterPrimitiveFloat(_UniffiConverterPrimitive): @classmethod - def check_lower(cls, value): + def check(cls, value): try: value = value.__float__() except Exception: raise TypeError("must be real number, not {}".format(type(value).__name__)) if not isinstance(value, float): raise TypeError("__float__ returned non-float (type {})".format(type(value).__name__)) + return super().check(value) # Helper class for wrapper types that will always go through a _UniffiRustBuffer. # Classes should inherit from this and implement the `read` and `write` static methods. diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RustBufferTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RustBufferTemplate.py index 44e0ba1001b2..c317a632fce3 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RustBufferTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/RustBufferTemplate.py @@ -1,16 +1,12 @@ class _UniffiRustBuffer(ctypes.Structure): _fields_ = [ - ("capacity", ctypes.c_uint64), - ("len", ctypes.c_uint64), + ("capacity", ctypes.c_int32), + ("len", ctypes.c_int32), ("data", ctypes.POINTER(ctypes.c_char)), ] @staticmethod - def default(): - return _UniffiRustBuffer(0, 0, None) - - @staticmethod def alloc(size): return _rust_call(_UniffiLib.{{ ci.ffi_rustbuffer_alloc().name() }}, size) @@ -141,6 +137,9 @@ class _UniffiRustBufferStream: def read_double(self): return self._unpack_from(8, ">d") + def read_c_size_t(self): + return self._unpack_from(ctypes.sizeof(ctypes.c_size_t) , "@N") + class _UniffiRustBufferBuilder: """ Helper for structured writing of bytes into a _UniffiRustBuffer. diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/SequenceTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/SequenceTemplate.py index 3c30d9f9f50e..3c9f5a45961a 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/SequenceTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/SequenceTemplate.py @@ -2,11 +2,6 @@ class {{ ffi_converter_name}}(_UniffiConverterRustBuffer): @classmethod - def check_lower(cls, value): - for item in value: - {{ inner_ffi_converter }}.check_lower(item) - - @classmethod def write(cls, value, buf): items = len(value) buf.write_i32(items) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/StringHelper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/StringHelper.py index d574edd09fa8..40890b6abc16 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/StringHelper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/StringHelper.py @@ -1,6 +1,6 @@ class _UniffiConverterString: @staticmethod - def check_lower(value): + def check(value): if not isinstance(value, str): raise TypeError("argument must be str, not {}".format(type(value).__name__)) return value @@ -15,6 +15,7 @@ class _UniffiConverterString: @staticmethod def write(value, buf): + value = _UniffiConverterString.check(value) utf8_bytes = value.encode("utf-8") buf.write_i32(len(utf8_bytes)) buf.write(utf8_bytes) @@ -26,6 +27,7 @@ class _UniffiConverterString: @staticmethod def lower(value): + value = _UniffiConverterString.check(value) with _UniffiRustBuffer.alloc_with_builder() as builder: builder.write(value.encode("utf-8")) return builder.finalize() diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/TimestampHelper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/TimestampHelper.py index 76d7f8bcdbaa..8402f6095d38 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/TimestampHelper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/TimestampHelper.py @@ -18,10 +18,6 @@ class _UniffiConverterTimestamp(_UniffiConverterRustBuffer): return datetime.datetime.fromtimestamp(0, tz=datetime.timezone.utc) - datetime.timedelta(seconds=-seconds, microseconds=microseconds) @staticmethod - def check_lower(value): - pass - - @staticmethod def write(value, buf): if value >= datetime.datetime.fromtimestamp(0, datetime.timezone.utc): sign = 1 diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/TopLevelFunctionTemplate.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/TopLevelFunctionTemplate.py index 230b9e853f83..f258b60a1c0a 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/TopLevelFunctionTemplate.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/TopLevelFunctionTemplate.py @@ -1,15 +1,7 @@ {%- if func.is_async() %} -{%- match func.return_type() -%} -{%- when Some with (return_type) %} -async def {{ func.name()|fn_name }}({%- call py::arg_list_decl(func) -%}) -> "{{ return_type|type_name }}": -{% when None %} -async def {{ func.name()|fn_name }}({%- call py::arg_list_decl(func) -%}) -> None: -{% endmatch %} - - {%- call py::docstring(func, 4) %} - {%- call py::setup_args(func) %} - return await _uniffi_rust_call_async( +def {{ func.name()|fn_name }}({%- call py::arg_list_decl(func) -%}): + return _uniffi_rust_call_async( _UniffiLib.{{ func.ffi_func().name() }}({% call py::arg_list_lowered(func) %}), _UniffiLib.{{func.ffi_rust_future_poll(ci) }}, _UniffiLib.{{func.ffi_rust_future_complete(ci) }}, @@ -21,7 +13,13 @@ async def {{ func.name()|fn_name }}({%- call py::arg_list_decl(func) -%}) -> Non {%- when None %} lambda val: None, {% endmatch %} - {% call py::error_ffi_converter(func) %} + # Error FFI converter + {%- match func.throws_type() %} + {%- when Some(e) %} + {{ e|ffi_converter_name }}, + {%- when None %} + None, + {%- endmatch %} ) {%- else %} @@ -29,13 +27,11 @@ async def {{ func.name()|fn_name }}({%- call py::arg_list_decl(func) -%}) -> Non {%- when Some with (return_type) %} def {{ func.name()|fn_name }}({%- call py::arg_list_decl(func) -%}) -> "{{ return_type|type_name }}": - {%- call py::docstring(func, 4) %} {%- call py::setup_args(func) %} return {{ return_type|lift_fn }}({% call py::to_ffi_call(func) %}) {% when None %} -def {{ func.name()|fn_name }}({%- call py::arg_list_decl(func) -%}) -> None: - {%- call py::docstring(func, 4) %} +def {{ func.name()|fn_name }}({%- call py::arg_list_decl(func) -%}): {%- call py::setup_args(func) %} {% call py::to_ffi_call(func) %} {% endmatch %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Types.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Types.py index 4aaed253e018..5e05314c37a5 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Types.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/Types.py @@ -85,7 +85,7 @@ {%- when Type::Map { key_type, value_type } %} {%- include "MapTemplate.py" %} -{%- when Type::CallbackInterface { name, module_path } %} +{%- when Type::CallbackInterface { name: id, module_path } %} {%- include "CallbackInterfaceTemplate.py" %} {%- when Type::Custom { name, module_path, builtin } %} @@ -94,6 +94,9 @@ {%- when Type::External { name, module_path, namespace, kind, tagged } %} {%- include "ExternalTemplate.py" %} +{%- when Type::ForeignExecutor %} +{%- include "ForeignExecutorTemplate.py" %} + {%- else %} {%- endmatch %} {%- endfor %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt16Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt16Helper.py index 039bf76162f8..081c6731ce96 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt16Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt16Helper.py @@ -8,5 +8,5 @@ class _UniffiConverterUInt16(_UniffiConverterPrimitiveInt): return buf.read_u16() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_u16(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt32Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt32Helper.py index 1650bf9b609f..b80e75177d48 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt32Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt32Helper.py @@ -8,5 +8,5 @@ class _UniffiConverterUInt32(_UniffiConverterPrimitiveInt): return buf.read_u32() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_u32(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt64Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt64Helper.py index f354545e26be..4b87e58547fa 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt64Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt64Helper.py @@ -8,5 +8,5 @@ class _UniffiConverterUInt64(_UniffiConverterPrimitiveInt): return buf.read_u64() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_u64(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt8Helper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt8Helper.py index cee130b4d90f..33026706f26c 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt8Helper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/UInt8Helper.py @@ -8,5 +8,5 @@ class _UniffiConverterUInt8(_UniffiConverterPrimitiveInt): return buf.read_u8() @staticmethod - def write(value, buf): + def write_unchecked(value, buf): buf.write_u8(value) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/macros.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/macros.py index 6818a8c10708..ef3b1bb94d34 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/macros.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/macros.py @@ -5,29 +5,27 @@ #} {%- macro to_ffi_call(func) -%} -{%- call _to_ffi_call_with_prefix_arg("", func) %} + {%- match func.throws_type() -%} + {%- when Some with (e) -%} +_rust_call_with_error({{ e|ffi_converter_name }}, + {%- else -%} +_rust_call( + {%- endmatch -%} + _UniffiLib.{{ func.ffi_func().name() }}, + {%- call arg_list_lowered(func) -%} +) {%- endmacro -%} {%- macro to_ffi_call_with_prefix(prefix, func) -%} -{%- call _to_ffi_call_with_prefix_arg(format!("{},", prefix), func) %} -{%- endmacro -%} - -{%- macro _to_ffi_call_with_prefix_arg(prefix, func) -%} -{%- match func.throws_type() -%} -{%- when Some with (e) -%} -{%- match e -%} -{%- when Type::Enum { name, module_path } -%} -_rust_call_with_error({{ e|ffi_converter_name }}, -{%- when Type::Object { name, module_path, imp } -%} -_rust_call_with_error({{ e|ffi_converter_name }}__as_error, -{%- else %} -# unsupported error type! -{%- endmatch %} -{%- else -%} + {%- match func.throws_type() -%} + {%- when Some with (e) -%} +_rust_call_with_error( + {{ e|ffi_converter_name }}, + {%- else -%} _rust_call( -{%- endmatch -%} + {%- endmatch -%} _UniffiLib.{{ func.ffi_func().name() }}, - {{- prefix }} + {{- prefix }}, {%- call arg_list_lowered(func) -%} ) {%- endmacro -%} @@ -39,19 +37,6 @@ _rust_call( {%- endfor %} {%- endmacro -%} -{%- macro docstring_value(maybe_docstring, indent_spaces) %} -{%- match maybe_docstring %} -{%- when Some(docstring) %} -{{ docstring|docstring(indent_spaces) }} -{{ "" }} -{%- else %} -{%- endmatch %} -{%- endmacro %} - -{%- macro docstring(defn, indent_spaces) %} -{%- call docstring_value(defn.docstring(), indent_spaces) %} -{%- endmacro %} - {#- // Arglist as used in Python declarations of methods, functions and constructors. // Note the var_name and type_name filters. @@ -91,7 +76,6 @@ _rust_call( if {{ arg.name()|var_name }} is _DEFAULT: {{ arg.name()|var_name }} = {{ literal|literal_py(arg.as_type().borrow()) }} {%- endmatch %} - {{ arg|check_lower_fn }}({{ arg.name()|var_name }}) {% endfor -%} {%- endmacro -%} @@ -107,7 +91,6 @@ _rust_call( if {{ arg.name()|var_name }} is _DEFAULT: {{ arg.name()|var_name }} = {{ literal|literal_py(arg.as_type().borrow()) }} {%- endmatch %} - {{ arg|check_lower_fn }}({{ arg.name()|var_name }}) {% endfor -%} {%- endmacro -%} @@ -117,18 +100,11 @@ _rust_call( {%- macro method_decl(py_method_name, meth) %} {% if meth.is_async() %} -{%- match meth.return_type() %} -{%- when Some with (return_type) %} - async def {{ py_method_name }}(self, {% call arg_list_decl(meth) %}) -> "{{ return_type|type_name }}": -{%- when None %} - async def {{ py_method_name }}(self, {% call arg_list_decl(meth) %}) -> None: -{% endmatch %} - - {%- call docstring(meth, 8) %} + def {{ py_method_name }}(self, {% call arg_list_decl(meth) %}): {%- call setup_args_extra_indent(meth) %} - return await _uniffi_rust_call_async( + return _uniffi_rust_call_async( _UniffiLib.{{ meth.ffi_func().name() }}( - self._uniffi_clone_pointer(), {% call arg_list_lowered(meth) %} + self._pointer, {% call arg_list_lowered(meth) %} ), _UniffiLib.{{ meth.ffi_rust_future_poll(ci) }}, _UniffiLib.{{ meth.ffi_rust_future_complete(ci) }}, @@ -140,7 +116,13 @@ _rust_call( {%- when None %} lambda val: None, {% endmatch %} - {% call error_ffi_converter(meth) %} + # Error FFI converter + {%- match meth.throws_type() %} + {%- when Some(e) %} + {{ e|ffi_converter_name }}, + {%- when None %} + None, + {%- endmatch %} ) {%- else -%} @@ -149,36 +131,17 @@ _rust_call( {%- when Some with (return_type) %} def {{ py_method_name }}(self, {% call arg_list_decl(meth) %}) -> "{{ return_type|type_name }}": - {%- call docstring(meth, 8) %} {%- call setup_args_extra_indent(meth) %} return {{ return_type|lift_fn }}( - {% call to_ffi_call_with_prefix("self._uniffi_clone_pointer()", meth) %} + {% call to_ffi_call_with_prefix("self._pointer", meth) %} ) {%- when None %} - def {{ py_method_name }}(self, {% call arg_list_decl(meth) %}) -> None: - {%- call docstring(meth, 8) %} + def {{ py_method_name }}(self, {% call arg_list_decl(meth) %}): {%- call setup_args_extra_indent(meth) %} - {% call to_ffi_call_with_prefix("self._uniffi_clone_pointer()", meth) %} + {% call to_ffi_call_with_prefix("self._pointer", meth) %} {% endmatch %} {% endif %} {% endmacro %} - -{%- macro error_ffi_converter(func) %} - # Error FFI converter -{% match func.throws_type() %} -{%- when Some(e) %} -{%- match e -%} -{%- when Type::Enum { name, module_path } -%} - {{ e|ffi_converter_name }}, -{%- when Type::Object { name, module_path, imp } -%} - {{ e|ffi_converter_name }}__as_error, -{%- else %} - # unsupported error type! -{%- endmatch %} -{%- when None %} - None, -{%- endmatch %} -{% endmacro %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/wrapper.py b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/wrapper.py index 1ccd6821c00b..24c3290ff7c1 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/templates/wrapper.py +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/templates/wrapper.py @@ -1,5 +1,3 @@ -{%- call py::docstring_value(ci.namespace_docstring(), 0) %} - # This file was autogenerated by some hot garbage in the `uniffi` crate. # Trust me, you don't want to mess with it! @@ -15,7 +13,6 @@ # compile the rust component. The easiest way to ensure this is to bundle the Python # helpers directly inline like we're doing here. -from __future__ import annotations import os import sys import ctypes @@ -23,9 +20,6 @@ import enum import struct import contextlib import datetime -import threading -import itertools -import traceback import typing {%- if ci.has_async_fns() %} import asyncio @@ -40,20 +34,20 @@ _DEFAULT = object() {% include "RustBufferTemplate.py" %} {% include "Helpers.py" %} -{% include "HandleMap.py" %} +{% include "PointerManager.py" %} {% include "RustBufferHelper.py" %} # Contains loading, initialization code, and the FFI Function declarations. {% include "NamespaceLibraryTemplate.py" %} -# Public interface members begin here. -{{ type_helper_code }} - # Async support {%- if ci.has_async_fns() %} {%- include "Async.py" %} {%- endif %} +# Public interface members begin here. +{{ type_helper_code }} + {%- for func in ci.function_definitions() %} {%- include "TopLevelFunctionTemplate.py" %} {%- endfor %} @@ -75,9 +69,6 @@ __all__ = [ {%- for c in ci.callback_interface_definitions() %} "{{ c.name()|class_name }}", {%- endfor %} - {%- if ci.has_async_fns() %} - "uniffi_set_event_loop", - {%- endif %} ] {% import "macros.py" as py %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/test.rs b/third_party/rust/uniffi_bindgen/src/bindings/python/test.rs index 0c23140b3326..0fcf09996f12 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/test.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/test.rs @@ -2,8 +2,10 @@ License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use crate::bindings::TargetLanguage; -use crate::{bindings::RunScriptOptions, library_mode::generate_bindings, BindingGeneratorDefault}; +use crate::{ + bindings::{RunScriptOptions, TargetLanguage}, + library_mode::generate_bindings, +}; use anyhow::{Context, Result}; use camino::Utf8Path; use std::env; @@ -32,18 +34,14 @@ pub fn run_script( args: Vec, _options: &RunScriptOptions, ) -> Result<()> { - let script_path = Utf8Path::new(script_file).canonicalize_utf8()?; + let script_path = Utf8Path::new(".").join(script_file).canonicalize_utf8()?; let test_helper = UniFFITestHelper::new(crate_name)?; let out_dir = test_helper.create_out_dir(tmp_dir, &script_path)?; let cdylib_path = test_helper.copy_cdylib_to_out_dir(&out_dir)?; generate_bindings( &cdylib_path, None, - &BindingGeneratorDefault { - target_languages: vec![TargetLanguage::Python], - try_format_code: false, - }, - None, + &[TargetLanguage::Python], &out_dir, false, )?; diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/gen_ruby/mod.rs b/third_party/rust/uniffi_bindgen/src/bindings/ruby/gen_ruby/mod.rs index 04841b459c9f..1f1bf8e299d3 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/ruby/gen_ruby/mod.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/gen_ruby/mod.rs @@ -2,39 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use anyhow::{bail, Result}; +use anyhow::Result; use askama::Template; -use camino::Utf8Path; use heck::{ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase}; use serde::{Deserialize, Serialize}; use std::borrow::Borrow; use std::collections::HashMap; -use crate::bindings::ruby; use crate::interface::*; -use crate::{BindingGenerator, BindingsConfig}; - -pub struct RubyBindingGenerator; -impl BindingGenerator for RubyBindingGenerator { - type Config = Config; - - fn write_bindings( - &self, - ci: &ComponentInterface, - config: &Config, - out_dir: &Utf8Path, - try_format_code: bool, - ) -> Result<()> { - ruby::write_bindings(config, ci, out_dir, try_format_code) - } - - fn check_library_path(&self, library_path: &Utf8Path, cdylib_name: Option<&str>) -> Result<()> { - if cdylib_name.is_none() { - bail!("Generate bindings for Ruby requires a cdylib, but {library_path} was given"); - } - Ok(()) - } -} +use crate::BindingsConfig; const RESERVED_WORDS: &[&str] = &[ "alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else", @@ -81,6 +57,7 @@ pub fn canonical_name(t: &Type) -> String { Type::CallbackInterface { name, .. } => format!("CallbackInterface{name}"), Type::Timestamp => "Timestamp".into(), Type::Duration => "Duration".into(), + Type::ForeignExecutor => "ForeignExecutor".into(), // Recursive types. // These add a prefix to the name of the underlying type. // The component API definition cannot give names to recursive types, so as long as the @@ -173,20 +150,20 @@ mod filters { FfiType::UInt64 => ":uint64".to_string(), FfiType::Float32 => ":float".to_string(), FfiType::Float64 => ":double".to_string(), - FfiType::Handle => ":uint64".to_string(), FfiType::RustArcPtr(_) => ":pointer".to_string(), FfiType::RustBuffer(_) => "RustBuffer.by_value".to_string(), - FfiType::RustCallStatus => "RustCallStatus".to_string(), FfiType::ForeignBytes => "ForeignBytes".to_string(), - FfiType::Callback(_) => unimplemented!("FFI Callbacks not implemented"), - // Note: this can't just be `unimplemented!()` because some of the FFI function - // definitions use references. Those FFI functions aren't actually used, so we just - // pick something that runs and makes some sense. Revisit this once the references - // are actually implemented. - FfiType::Reference(_) => ":pointer".to_string(), - FfiType::VoidPointer => ":pointer".to_string(), - FfiType::Struct(_) => { - unimplemented!("Structs are not implemented") + FfiType::ForeignCallback => unimplemented!("Callback interfaces are not implemented"), + FfiType::ForeignExecutorCallback => { + unimplemented!("Foreign executors are not implemented") + } + FfiType::ForeignExecutorHandle => { + unimplemented!("Foreign executors are not implemented") + } + FfiType::RustFutureHandle + | FfiType::RustFutureContinuationCallback + | FfiType::RustFutureContinuationData => { + unimplemented!("Async functions are not implemented") } }) } @@ -202,8 +179,7 @@ mod filters { } // use the double-quote form to match with the other languages, and quote escapes. Literal::String(s) => format!("\"{s}\""), - Literal::None => "nil".into(), - Literal::Some { inner } => literal_rb(inner)?, + Literal::Null => "nil".into(), Literal::EmptySequence => "[]".into(), Literal::EmptyMap => "{}".into(), Literal::Enum(v, type_) => match type_ { @@ -288,24 +264,7 @@ mod filters { } Type::External { .. } => panic!("No support for external types, yet"), Type::Custom { .. } => panic!("No support for custom types, yet"), - }) - } - - pub fn check_lower_rb(nm: &str, type_: &Type) -> Result { - Ok(match type_ { - Type::Object { name, .. } => { - format!("({}.uniffi_check_lower {nm})", class_name_rb(name)?) - } - Type::Enum { .. } - | Type::Record { .. } - | Type::Optional { .. } - | Type::Sequence { .. } - | Type::Map { .. } => format!( - "RustBuffer.check_lower_{}({})", - class_name_rb(&canonical_name(type_))?, - nm - ), - _ => "".to_owned(), + Type::ForeignExecutor => unimplemented!("Foreign executors are not implemented"), }) } @@ -324,7 +283,7 @@ mod filters { Type::Boolean => format!("({nm} ? 1 : 0)"), Type::String => format!("RustBuffer.allocFromString({nm})"), Type::Bytes => format!("RustBuffer.allocFromBytes({nm})"), - Type::Object { name, .. } => format!("({}.uniffi_lower {nm})", class_name_rb(name)?), + Type::Object { name, .. } => format!("({}._uniffi_lower {nm})", class_name_rb(name)?), Type::CallbackInterface { .. } => { panic!("No support for lowering callback interfaces yet") } @@ -341,6 +300,7 @@ mod filters { ), Type::External { .. } => panic!("No support for lowering external types, yet"), Type::Custom { .. } => panic!("No support for lowering custom types, yet"), + Type::ForeignExecutor => unimplemented!("Foreign executors are not implemented"), }) } @@ -358,7 +318,7 @@ mod filters { Type::Boolean => format!("1 == {nm}"), Type::String => format!("{nm}.consumeIntoString"), Type::Bytes => format!("{nm}.consumeIntoBytes"), - Type::Object { name, .. } => format!("{}.uniffi_allocate({nm})", class_name_rb(name)?), + Type::Object { name, .. } => format!("{}._uniffi_allocate({nm})", class_name_rb(name)?), Type::CallbackInterface { .. } => { panic!("No support for lifting callback interfaces, yet") } @@ -381,6 +341,7 @@ mod filters { ), Type::External { .. } => panic!("No support for lifting external types, yet"), Type::Custom { .. } => panic!("No support for lifting custom types, yet"), + Type::ForeignExecutor => unimplemented!("Foreign executors are not implemented"), }) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/ObjectTemplate.rb b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/ObjectTemplate.rb index ba2caf738072..677c5c729bf8 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/ObjectTemplate.rb +++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/ObjectTemplate.rb @@ -2,18 +2,18 @@ class {{ obj.name()|class_name_rb }} # A private helper for initializing instances of the class from a raw pointer, # bypassing any initialization logic and ensuring they are GC'd properly. - def self.uniffi_allocate(pointer) + def self._uniffi_allocate(pointer) pointer.autorelease = false inst = allocate inst.instance_variable_set :@pointer, pointer - ObjectSpace.define_finalizer(inst, uniffi_define_finalizer_by_pointer(pointer, inst.object_id)) + ObjectSpace.define_finalizer(inst, _uniffi_define_finalizer_by_pointer(pointer, inst.object_id)) return inst end # A private helper for registering an object finalizer. # N.B. it's important that this does not capture a reference # to the actual instance, only its underlying pointer. - def self.uniffi_define_finalizer_by_pointer(pointer, object_id) + def self._uniffi_define_finalizer_by_pointer(pointer, object_id) Proc.new do |_id| {{ ci.namespace()|class_name_rb }}.rust_call( :{{ obj.ffi_object_free().name() }}, @@ -25,41 +25,31 @@ class {{ obj.name()|class_name_rb }} # A private helper for lowering instances into a raw pointer. # This does an explicit typecheck, because accidentally lowering a different type of # object in a place where this type is expected, could lead to memory unsafety. - def self.uniffi_check_lower(inst) + def self._uniffi_lower(inst) if not inst.is_a? self raise TypeError.new "Expected a {{ obj.name()|class_name_rb }} instance, got #{inst}" end - end - - def uniffi_clone_pointer() - return {{ ci.namespace()|class_name_rb }}.rust_call( - :{{ obj.ffi_object_clone().name() }}, - @pointer - ) - end - - def self.uniffi_lower(inst) - return inst.uniffi_clone_pointer() + return inst.instance_variable_get :@pointer end {%- match obj.primary_constructor() %} {%- when Some with (cons) %} def initialize({% call rb::arg_list_decl(cons) -%}) - {%- call rb::setup_args_extra_indent(cons) %} + {%- call rb::coerce_args_extra_indent(cons) %} pointer = {% call rb::to_ffi_call(cons) %} @pointer = pointer - ObjectSpace.define_finalizer(self, self.class.uniffi_define_finalizer_by_pointer(pointer, self.object_id)) + ObjectSpace.define_finalizer(self, self.class._uniffi_define_finalizer_by_pointer(pointer, self.object_id)) end {%- when None %} {%- endmatch %} {% for cons in obj.alternate_constructors() -%} def self.{{ cons.name()|fn_name_rb }}({% call rb::arg_list_decl(cons) %}) - {%- call rb::setup_args_extra_indent(cons) %} + {%- call rb::coerce_args_extra_indent(cons) %} # Call the (fallible) function before creating any half-baked object instances. # Lightly yucky way to bypass the usual "initialize" logic # and just create a new instance with the required pointer. - return uniffi_allocate({% call rb::to_ffi_call(cons) %}) + return _uniffi_allocate({% call rb::to_ffi_call(cons) %}) end {% endfor %} @@ -68,15 +58,15 @@ class {{ obj.name()|class_name_rb }} {%- when Some with (return_type) -%} def {{ meth.name()|fn_name_rb }}({% call rb::arg_list_decl(meth) %}) - {%- call rb::setup_args_extra_indent(meth) %} - result = {% call rb::to_ffi_call_with_prefix("uniffi_clone_pointer()", meth) %} + {%- call rb::coerce_args_extra_indent(meth) %} + result = {% call rb::to_ffi_call_with_prefix("@pointer", meth) %} return {{ "result"|lift_rb(return_type) }} end {%- when None -%} def {{ meth.name()|fn_name_rb }}({% call rb::arg_list_decl(meth) %}) - {%- call rb::setup_args_extra_indent(meth) %} - {% call rb::to_ffi_call_with_prefix("uniffi_clone_pointer()", meth) %} + {%- call rb::coerce_args_extra_indent(meth) %} + {% call rb::to_ffi_call_with_prefix("@pointer", meth) %} end {% endmatch %} {% endfor %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RecordTemplate.rb b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RecordTemplate.rb index b5a201b248b9..c940b3106053 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RecordTemplate.rb +++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RecordTemplate.rb @@ -2,12 +2,7 @@ class {{ rec.name()|class_name_rb }} attr_reader {% for field in rec.fields() %}:{{ field.name()|var_name_rb }}{% if loop.last %}{% else %}, {% endif %}{%- endfor %} - def initialize({% for field in rec.fields() %}{{ field.name()|var_name_rb -}}: - {%- match field.default_value() %} - {%- when Some with(literal) %} {{ literal|literal_rb }} - {%- else %} - {%- endmatch %} - {%- if loop.last %}{% else %}, {% endif -%}{% endfor %}) + def initialize({% for field in rec.fields() %}{{ field.name()|var_name_rb }}{% if loop.last %}{% else %}, {% endif %}{% endfor %}) {%- for field in rec.fields() %} @{{ field.name()|var_name_rb }} = {{ field.name()|var_name_rb }} {%- endfor %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb index d15c0bbe762f..8749139116bf 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb +++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferBuilder.rb @@ -163,7 +163,7 @@ class RustBufferBuilder # The Object type {{ object_name }}. def write_{{ canonical_type_name }}(obj) - pointer = {{ object_name|class_name_rb}}.uniffi_lower obj + pointer = {{ object_name|class_name_rb}}._uniffi_lower obj pack_into(8, 'Q>', pointer.address) end diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferStream.rb b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferStream.rb index f9b0806abc4a..b085dddf15e8 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferStream.rb +++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferStream.rb @@ -155,7 +155,7 @@ class RustBufferStream def read{{ canonical_type_name }} pointer = FFI::Pointer.new unpack_from 8, 'Q>' - return {{ object_name|class_name_rb }}.uniffi_allocate(pointer) + return {{ object_name|class_name_rb }}._uniffi_allocate(pointer) end {% when Type::Enum { name, module_path } -%} @@ -237,7 +237,7 @@ class RustBufferStream def read{{ canonical_type_name }} {{ rec.name()|class_name_rb }}.new( {%- for field in rec.fields() %} - {{ field.name()|var_name_rb }}: read{{ canonical_name(field.as_type().borrow()).borrow()|class_name_rb }}{% if loop.last %}{% else %},{% endif %} + read{{ canonical_name(field.as_type().borrow()).borrow()|class_name_rb }}{% if loop.last %}{% else %},{% endif %} {%- endfor %} ) end diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferTemplate.rb b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferTemplate.rb index 452d9831cded..0194c9666def 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferTemplate.rb +++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/RustBufferTemplate.rb @@ -1,6 +1,6 @@ class RustBuffer < FFI::Struct - layout :capacity, :uint64, - :len, :uint64, + layout :capacity, :int32, + :len, :int32, :data, :pointer def self.alloc(size) @@ -128,12 +128,6 @@ class RustBuffer < FFI::Struct {%- let rec = ci|get_record_definition(record_name) -%} # The Record type {{ record_name }}. - def self.check_lower_{{ canonical_type_name }}(v) - {%- for field in rec.fields() %} - {{ "v.{}"|format(field.name()|var_name_rb)|check_lower_rb(field.as_type().borrow()) }} - {%- endfor %} - end - def self.alloc_from_{{ canonical_type_name }}(v) RustBuffer.allocWithBuilder do |builder| builder.write_{{ canonical_type_name }}(v) @@ -152,19 +146,6 @@ class RustBuffer < FFI::Struct {%- let e = ci|get_enum_definition(enum_name) -%} # The Enum type {{ enum_name }}. - def self.check_lower_{{ canonical_type_name }}(v) - {%- if !e.is_flat() %} - {%- for variant in e.variants() %} - if v.{{ variant.name()|var_name_rb }}? - {%- for field in variant.fields() %} - {{ "v.{}"|format(field.name())|check_lower_rb(field.as_type().borrow()) }} - {%- endfor %} - return - end - {%- endfor %} - {%- endif %} - end - def self.alloc_from_{{ canonical_type_name }}(v) RustBuffer.allocWithBuilder do |builder| builder.write_{{ canonical_type_name }}(v) @@ -182,12 +163,6 @@ class RustBuffer < FFI::Struct {% when Type::Optional { inner_type } -%} # The Optional type for {{ canonical_name(inner_type) }}. - def self.check_lower_{{ canonical_type_name }}(v) - if not v.nil? - {{ "v"|check_lower_rb(inner_type.borrow()) }} - end - end - def self.alloc_from_{{ canonical_type_name }}(v) RustBuffer.allocWithBuilder do |builder| builder.write_{{ canonical_type_name }}(v) @@ -204,12 +179,6 @@ class RustBuffer < FFI::Struct {% when Type::Sequence { inner_type } -%} # The Sequence type for {{ canonical_name(inner_type) }}. - def self.check_lower_{{ canonical_type_name }}(v) - v.each do |item| - {{ "item"|check_lower_rb(inner_type.borrow()) }} - end - end - def self.alloc_from_{{ canonical_type_name }}(v) RustBuffer.allocWithBuilder do |builder| builder.write_{{ canonical_type_name }}(v) @@ -226,13 +195,6 @@ class RustBuffer < FFI::Struct {% when Type::Map { key_type: k, value_type: inner_type } -%} # The Map type for {{ canonical_name(inner_type) }}. - def self.check_lower_{{ canonical_type_name }}(v) - v.each do |k, v| - {{ "k"|check_lower_rb(k.borrow()) }} - {{ "v"|check_lower_rb(inner_type.borrow()) }} - end - end - def self.alloc_from_{{ canonical_type_name }}(v) RustBuffer.allocWithBuilder do |builder| builder.write_{{ canonical_type_name }}(v) diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/TopLevelFunctionTemplate.rb b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/TopLevelFunctionTemplate.rb index b6dce0effab4..13214cf31b53 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/TopLevelFunctionTemplate.rb +++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/TopLevelFunctionTemplate.rb @@ -2,7 +2,7 @@ {%- when Some with (return_type) %} def self.{{ func.name()|fn_name_rb }}({%- call rb::arg_list_decl(func) -%}) - {%- call rb::setup_args(func) %} + {%- call rb::coerce_args(func) %} result = {% call rb::to_ffi_call(func) %} return {{ "result"|lift_rb(return_type) }} end @@ -10,7 +10,7 @@ end {% when None %} def self.{{ func.name()|fn_name_rb }}({%- call rb::arg_list_decl(func) -%}) - {%- call rb::setup_args(func) %} + {%- call rb::coerce_args(func) %} {% call rb::to_ffi_call(func) %} end {% endmatch %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/macros.rb b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/macros.rb index 59fa4ef4cc27..8dc3e5e613b5 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/macros.rb +++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/templates/macros.rb @@ -60,16 +60,14 @@ [{%- for arg in func.arguments() -%}{{ arg.type_().borrow()|type_ffi }}, {% endfor -%} RustCallStatus.by_ref] {%- endmacro -%} -{%- macro setup_args(func) %} +{%- macro coerce_args(func) %} {%- for arg in func.arguments() %} - {{ arg.name() }} = {{ arg.name()|coerce_rb(ci.namespace()|class_name_rb, arg.as_type().borrow()) }} - {{ arg.name()|check_lower_rb(arg.as_type().borrow()) }} + {{ arg.name() }} = {{ arg.name()|coerce_rb(ci.namespace()|class_name_rb, arg.as_type().borrow()) -}} {% endfor -%} {%- endmacro -%} -{%- macro setup_args_extra_indent(meth) %} - {%- for arg in meth.arguments() %} +{%- macro coerce_args_extra_indent(func) %} + {%- for arg in func.arguments() %} {{ arg.name() }} = {{ arg.name()|coerce_rb(ci.namespace()|class_name_rb, arg.as_type().borrow()) }} - {{ arg.name()|check_lower_rb(arg.as_type().borrow()) }} {%- endfor %} {%- endmacro -%} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/ruby/test.rs b/third_party/rust/uniffi_bindgen/src/bindings/ruby/test.rs index 88f770b9dc32..03da37d567a0 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/ruby/test.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/ruby/test.rs @@ -4,7 +4,6 @@ License, v. 2.0. If a copy of the MPL was not distributed with this use crate::bindings::TargetLanguage; use crate::library_mode::generate_bindings; -use crate::BindingGeneratorDefault; use anyhow::{bail, Context, Result}; use camino::Utf8Path; use std::env; @@ -31,21 +30,11 @@ pub fn test_script_command( fixture_name: &str, script_file: &str, ) -> Result { - let script_path = Utf8Path::new(script_file).canonicalize_utf8()?; + let script_path = Utf8Path::new(".").join(script_file).canonicalize_utf8()?; let test_helper = UniFFITestHelper::new(fixture_name)?; let out_dir = test_helper.create_out_dir(tmp_dir, &script_path)?; let cdylib_path = test_helper.copy_cdylib_to_out_dir(&out_dir)?; - generate_bindings( - &cdylib_path, - None, - &BindingGeneratorDefault { - target_languages: vec![TargetLanguage::Ruby], - try_format_code: false, - }, - None, - &out_dir, - false, - )?; + generate_bindings(&cdylib_path, None, &[TargetLanguage::Ruby], &out_dir, false)?; let rubypath = env::var_os("RUBYLIB").unwrap_or_else(|| OsString::from("")); let rubypath = env::join_paths( diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/callback_interface.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/callback_interface.rs index dab89e0259d4..5d8b37e0af9b 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/callback_interface.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/callback_interface.rs @@ -6,25 +6,21 @@ use super::CodeType; #[derive(Debug)] pub struct CallbackInterfaceCodeType { - name: String, + id: String, } impl CallbackInterfaceCodeType { - pub fn new(name: String) -> Self { - Self { name } + pub fn new(id: String) -> Self { + Self { id } } } impl CodeType for CallbackInterfaceCodeType { fn type_label(&self) -> String { - super::SwiftCodeOracle.class_name(&self.name) + super::SwiftCodeOracle.class_name(&self.id) } fn canonical_name(&self) -> String { format!("CallbackInterface{}", self.type_label()) } - - fn initialization_fn(&self) -> Option { - Some(format!("uniffiCallbackInit{}", self.name)) - } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/compounds.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/compounds.rs index d89fdfd38646..8e6dddf3f918 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/compounds.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/compounds.rs @@ -30,9 +30,8 @@ impl CodeType for OptionalCodeType { fn literal(&self, literal: &Literal) -> String { match literal { - Literal::None => "nil".into(), - Literal::Some { inner } => super::SwiftCodeOracle.find(&self.inner).literal(inner), - _ => panic!("Invalid literal for Optional type: {literal:?}"), + Literal::Null => "nil".into(), + _ => super::SwiftCodeOracle.find(&self.inner).literal(literal), } } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs similarity index 51% copy from third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs copy to third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs index 0a46251d6d9a..b488b004cfe7 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs @@ -5,22 +5,19 @@ use super::CodeType; #[derive(Debug)] -pub struct ExternalCodeType { - name: String, -} - -impl ExternalCodeType { - pub fn new(name: String) -> Self { - Self { name } - } -} +pub struct ForeignExecutorCodeType; -impl CodeType for ExternalCodeType { +impl CodeType for ForeignExecutorCodeType { fn type_label(&self) -> String { - super::PythonCodeOracle.class_name(&self.name) + // On Swift, we define a struct to represent a ForeignExecutor + "UniFfiForeignExecutor".into() } fn canonical_name(&self) -> String { - format!("Type{}", self.name) + "ForeignExecutor".into() + } + + fn initialization_fn(&self) -> Option { + Some("uniffiInitForeignExecutor".into()) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/external.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/external.rs index 3960b7aae148..0b6728ba840e 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/external.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/external.rs @@ -17,7 +17,7 @@ impl ExternalCodeType { impl CodeType for ExternalCodeType { fn type_label(&self) -> String { - super::SwiftCodeOracle.class_name(&self.name) + self.name.clone() } fn canonical_name(&self) -> String { diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/mod.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/mod.rs index 16c162512367..12db4afc6664 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/mod.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/mod.rs @@ -10,49 +10,25 @@ use std::fmt::Debug; use anyhow::{Context, Result}; use askama::Template; -use camino::Utf8Path; -use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToUpperCamelCase}; +use heck::{ToLowerCamelCase, ToUpperCamelCase}; use serde::{Deserialize, Serialize}; use super::Bindings; use crate::backend::TemplateExpression; -use crate::bindings::swift; use crate::interface::*; -use crate::{BindingGenerator, BindingsConfig}; +use crate::BindingsConfig; mod callback_interface; mod compounds; mod custom; mod enum_; +mod executor; mod external; mod miscellany; mod object; mod primitives; mod record; -pub struct SwiftBindingGenerator; -impl BindingGenerator for SwiftBindingGenerator { - type Config = Config; - - fn write_bindings( - &self, - ci: &ComponentInterface, - config: &Config, - out_dir: &Utf8Path, - try_format_code: bool, - ) -> Result<()> { - swift::write_bindings(config, ci, out_dir, try_format_code) - } - - fn check_library_path( - &self, - _library_path: &Utf8Path, - _cdylib_name: Option<&str>, - ) -> Result<()> { - Ok(()) - } -} - /// A trait tor the implementation. trait CodeType: Debug { /// The language specific label used to reference this type. This will be used in @@ -220,8 +196,6 @@ pub struct Config { ffi_module_filename: Option, generate_module_map: Option, omit_argument_labels: Option, - generate_immutable_records: Option, - experimental_sendable_value_types: Option, #[serde(default)] custom_types: HashMap, } @@ -287,16 +261,6 @@ impl Config { pub fn omit_argument_labels(&self) -> bool { self.omit_argument_labels.unwrap_or(false) } - - /// Whether to generate immutable records (`let` instead of `var`) - pub fn generate_immutable_records(&self) -> bool { - self.generate_immutable_records.unwrap_or(false) - } - - /// Whether to mark value types as 'Sendable' - pub fn experimental_sendable_value_types(&self) -> bool { - self.experimental_sendable_value_types.unwrap_or(false) - } } impl BindingsConfig for Config { @@ -436,6 +400,7 @@ pub struct SwiftWrapper<'a> { ci: &'a ComponentInterface, type_helper_code: String, type_imports: BTreeSet, + has_async_fns: bool, } impl<'a> SwiftWrapper<'a> { pub fn new(config: Config, ci: &'a ComponentInterface) -> Self { @@ -447,6 +412,7 @@ impl<'a> SwiftWrapper<'a> { ci, type_helper_code, type_imports, + has_async_fns: ci.has_async_fns(), } } @@ -459,6 +425,10 @@ impl<'a> SwiftWrapper<'a> { .iter_types() .map(|t| SwiftCodeOracle.find(t)) .filter_map(|ct| ct.initialization_fn()) + .chain( + self.has_async_fns + .then(|| "uniffiInitContinuationCallback".into()), + ) .collect() } } @@ -494,11 +464,12 @@ impl SwiftCodeOracle { Type::Duration => Box::new(miscellany::DurationCodeType), Type::Enum { name, .. } => Box::new(enum_::EnumCodeType::new(name)), - Type::Object { name, imp, .. } => Box::new(object::ObjectCodeType::new(name, imp)), + Type::Object { name, .. } => Box::new(object::ObjectCodeType::new(name)), Type::Record { name, .. } => Box::new(record::RecordCodeType::new(name)), Type::CallbackInterface { name, .. } => { Box::new(callback_interface::CallbackInterfaceCodeType::new(name)) } + Type::ForeignExecutor => Box::new(executor::ForeignExecutorCodeType), Type::Optional { inner_type } => { Box::new(compounds::OptionalCodeType::new(*inner_type)) } @@ -538,22 +509,7 @@ impl SwiftCodeOracle { nm.to_string().to_lower_camel_case() } - /// Get the idiomatic Swift rendering of an FFI callback function name - fn ffi_callback_name(&self, nm: &str) -> String { - format!("Uniffi{}", nm.to_upper_camel_case()) - } - - /// Get the idiomatic Swift rendering of an FFI struct name - fn ffi_struct_name(&self, nm: &str) -> String { - format!("Uniffi{}", nm.to_upper_camel_case()) - } - - /// Get the idiomatic Swift rendering of an if guard name - fn if_guard_name(&self, nm: &str) -> String { - format!("UNIFFI_FFIDEF_{}", nm.to_shouty_snake_case()) - } - - fn ffi_type_label(&self, ffi_type: &FfiType) -> String { + fn ffi_type_label_raw(&self, ffi_type: &FfiType) -> String { match ffi_type { FfiType::Int8 => "Int8".into(), FfiType::UInt8 => "UInt8".into(), @@ -565,74 +521,40 @@ impl SwiftCodeOracle { FfiType::UInt64 => "UInt64".into(), FfiType::Float32 => "Float".into(), FfiType::Float64 => "Double".into(), - FfiType::Handle => "UInt64".into(), FfiType::RustArcPtr(_) => "UnsafeMutableRawPointer".into(), FfiType::RustBuffer(_) => "RustBuffer".into(), - FfiType::RustCallStatus => "RustCallStatus".into(), FfiType::ForeignBytes => "ForeignBytes".into(), - // Note: @escaping is required for Swift versions before 5.7 for callbacks passed into - // async functions. Swift 5.7 and later does not require it. We should probably remove - // it once we upgrade our minimum requirement to 5.7 or later. - FfiType::Callback(name) => format!("@escaping {}", self.ffi_callback_name(name)), - FfiType::Struct(name) => self.ffi_struct_name(name), - FfiType::Reference(inner) => { - format!("UnsafeMutablePointer<{}>", self.ffi_type_label(inner)) + FfiType::ForeignCallback => "ForeignCallback".into(), + FfiType::ForeignExecutorHandle => "Int".into(), + FfiType::ForeignExecutorCallback => "ForeignExecutorCallback".into(), + FfiType::RustFutureContinuationCallback => "UniFfiRustFutureContinuation".into(), + FfiType::RustFutureHandle | FfiType::RustFutureContinuationData => { + "UnsafeMutableRawPointer".into() } - FfiType::VoidPointer => "UnsafeMutableRawPointer".into(), } } - /// Default values for FFI types - /// - /// Used to set a default return value when returning an error - fn ffi_default_value(&self, return_type: Option<&FfiType>) -> String { - match return_type { - Some(t) => match t { - FfiType::UInt8 - | FfiType::Int8 - | FfiType::UInt16 - | FfiType::Int16 - | FfiType::UInt32 - | FfiType::Int32 - | FfiType::UInt64 - | FfiType::Int64 => "0".to_owned(), - FfiType::Float32 | FfiType::Float64 => "0.0".to_owned(), - FfiType::RustArcPtr(_) => "nil".to_owned(), - FfiType::RustBuffer(_) => "RustBuffer.empty()".to_owned(), - _ => unimplemented!("FFI return type: {t:?}"), - }, - // When we need to use a value for void returns, we use a `u8` placeholder - None => "0".to_owned(), + fn ffi_type_label(&self, ffi_type: &FfiType) -> String { + match ffi_type { + FfiType::ForeignCallback + | FfiType::ForeignExecutorCallback + | FfiType::RustFutureHandle + | FfiType::RustFutureContinuationCallback + | FfiType::RustFutureContinuationData => { + format!("{} _Nonnull", self.ffi_type_label_raw(ffi_type)) + } + _ => self.ffi_type_label_raw(ffi_type), } } fn ffi_canonical_name(&self, ffi_type: &FfiType) -> String { - self.ffi_type_label(ffi_type) - } - - /// Get the name of the protocol and class name for an object. - /// - /// If we support callback interfaces, the protocol name is the object name, and the class name is derived from that. - /// Otherwise, the class name is the object name and the protocol name is derived from that. - /// - /// This split determines what types `FfiConverter.lower()` inputs. If we support callback - /// interfaces, `lower` must lower anything that implements the protocol. If not, then lower - /// only lowers the concrete class. - fn object_names(&self, obj: &Object) -> (String, String) { - let class_name = self.class_name(obj.name()); - if obj.has_callback_interface() { - let impl_name = format!("{class_name}Impl"); - (class_name, impl_name) - } else { - (format!("{class_name}Protocol"), class_name) - } + self.ffi_type_label_raw(ffi_type) } } pub mod filters { use super::*; pub use crate::backend::filters::*; - use uniffi_meta::LiteralMetadata; fn oracle() -> &'static SwiftCodeOracle { &SwiftCodeOracle @@ -642,13 +564,6 @@ pub mod filters { Ok(oracle().find(&as_type.as_type()).type_label()) } - pub fn return_type_name(as_type: Option<&impl AsType>) -> Result { - Ok(match as_type { - Some(as_type) => oracle().find(&as_type.as_type()).type_label(), - None => "()".to_owned(), - }) - } - pub fn canonical_name(as_type: &impl AsType) -> Result { Ok(oracle().find(&as_type.as_type()).canonical_name()) } @@ -657,15 +572,6 @@ pub mod filters { Ok(oracle().find(&as_type.as_type()).ffi_converter_name()) } - pub fn ffi_error_converter_name(as_type: &impl AsType) -> Result { - // special handling for types used as errors. - let mut name = oracle().find(&as_type.as_type()).ffi_converter_name(); - if matches!(&as_type.as_type(), Type::Object { .. }) { - name.push_str("__as_error") - } - Ok(name) - } - pub fn lower_fn(as_type: &impl AsType) -> Result { Ok(oracle().find(&as_type.as_type()).lower()) } @@ -689,16 +595,6 @@ pub mod filters { Ok(oracle().find(&as_type.as_type()).literal(literal)) } - // Get the idiomatic Swift rendering of an individual enum variant's discriminant - pub fn variant_discr_literal(e: &Enum, index: &usize) -> Result { - let literal = e.variant_discr(*index).expect("invalid index"); - match literal { - LiteralMetadata::UInt(v, _, _) => Ok(v.to_string()), - LiteralMetadata::Int(v, _, _) => Ok(v.to_string()), - _ => unreachable!("expected an UInt!"), - } - } - /// Get the Swift type for an FFIType pub fn ffi_type_name(ffi_type: &FfiType) -> Result { Ok(oracle().ffi_type_label(ffi_type)) @@ -708,10 +604,6 @@ pub mod filters { Ok(oracle().ffi_canonical_name(ffi_type)) } - pub fn ffi_default_value(return_type: Option) -> Result { - Ok(oracle().ffi_default_value(return_type.as_ref())) - } - /// Like `ffi_type_name`, but used in `BridgingHeaderTemplate.h` which uses a slightly different /// names. pub fn header_ffi_type_name(ffi_type: &FfiType) -> Result { @@ -726,17 +618,18 @@ pub mod filters { FfiType::UInt64 => "uint64_t".into(), FfiType::Float32 => "float".into(), FfiType::Float64 => "double".into(), - FfiType::Handle => "uint64_t".into(), FfiType::RustArcPtr(_) => "void*_Nonnull".into(), FfiType::RustBuffer(_) => "RustBuffer".into(), - FfiType::RustCallStatus => "RustCallStatus".into(), FfiType::ForeignBytes => "ForeignBytes".into(), - FfiType::Callback(name) => { - format!("{} _Nonnull", SwiftCodeOracle.ffi_callback_name(name)) + FfiType::ForeignCallback => "ForeignCallback _Nonnull".into(), + FfiType::ForeignExecutorCallback => "UniFfiForeignExecutorCallback _Nonnull".into(), + FfiType::ForeignExecutorHandle => "size_t".into(), + FfiType::RustFutureContinuationCallback => { + "UniFfiRustFutureContinuation _Nonnull".into() + } + FfiType::RustFutureHandle | FfiType::RustFutureContinuationData => { + "void* _Nonnull".into() } - FfiType::Struct(name) => SwiftCodeOracle.ffi_struct_name(name), - FfiType::Reference(inner) => format!("{}* _Nonnull", header_ffi_type_name(inner)?), - FfiType::VoidPointer => "void* _Nonnull".into(), }) } @@ -771,30 +664,6 @@ pub mod filters { Ok(oracle().enum_variant_name(nm)) } - /// Get the idiomatic Swift rendering of an FFI callback function name - pub fn ffi_callback_name(nm: &str) -> Result { - Ok(oracle().ffi_callback_name(nm)) - } - - /// Get the idiomatic Swift rendering of an FFI struct name - pub fn ffi_struct_name(nm: &str) -> Result { - Ok(oracle().ffi_struct_name(nm)) - } - - /// Get the idiomatic Swift rendering of an if guard name - pub fn if_guard_name(nm: &str) -> Result { - Ok(oracle().if_guard_name(nm)) - } - - /// Get the idiomatic Swift rendering of docstring - pub fn docstring(docstring: &str, spaces: &i32) -> Result { - let middle = textwrap::indent(&textwrap::dedent(docstring), " * "); - let wrapped = format!("/**\n{middle}\n */"); - - let spaces = usize::try_from(*spaces).unwrap_or_default(); - Ok(textwrap::indent(&wrapped, &" ".repeat(spaces))) - } - pub fn error_handler(result: &ResultType) -> Result { Ok(match &result.throws_type { Some(t) => format!("{}.lift", ffi_converter_name(t)?), @@ -816,8 +685,4 @@ pub mod filters { } )) } - - pub fn object_names(obj: &Object) -> Result<(String, String), askama::Error> { - Ok(SwiftCodeOracle.object_names(obj)) - } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs similarity index 57% copy from third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs copy to third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs index 0a46251d6d9a..ea140c998d39 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/external.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs @@ -5,22 +5,22 @@ use super::CodeType; #[derive(Debug)] -pub struct ExternalCodeType { - name: String, +pub struct ObjectCodeType { + id: String, } -impl ExternalCodeType { - pub fn new(name: String) -> Self { - Self { name } +impl ObjectCodeType { + pub fn new(id: String) -> Self { + Self { id } } } -impl CodeType for ExternalCodeType { +impl CodeType for ObjectCodeType { fn type_label(&self) -> String { - super::PythonCodeOracle.class_name(&self.name) + super::SwiftCodeOracle.class_name(&self.id) } fn canonical_name(&self) -> String { - format!("Type{}", self.name) + format!("Type{}", self.id) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/primitives.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/primitives.rs index e0c670520ed3..86424658a3b2 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/primitives.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/primitives.rs @@ -9,11 +9,7 @@ use paste::paste; fn render_literal(literal: &Literal) -> String { fn typed_number(type_: &Type, num_str: String) -> String { - let unwrapped_type = match type_ { - Type::Optional { inner_type } => inner_type, - t => t, - }; - match unwrapped_type { + match type_ { // special case Int32. Type::Int32 => num_str, // otherwise use constructor e.g. UInt8(x) @@ -33,7 +29,7 @@ fn render_literal(literal: &Literal) -> String { super::SwiftCodeOracle.find(type_).type_label() ) } - _ => panic!("Unexpected literal: {num_str} for type: {type_:?}"), + _ => panic!("Unexpected literal: {num_str} is not a number"), } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Async.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Async.swift dissimilarity index 76% index e16f3108e1b6..695208861d63 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Async.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Async.swift @@ -1,116 +1,62 @@ -private let UNIFFI_RUST_FUTURE_POLL_READY: Int8 = 0 -private let UNIFFI_RUST_FUTURE_POLL_MAYBE_READY: Int8 = 1 - -fileprivate let uniffiContinuationHandleMap = UniffiHandleMap>() - -fileprivate func uniffiRustCallAsync( - rustFutureFunc: () -> UInt64, - pollFunc: (UInt64, @escaping UniffiRustFutureContinuationCallback, UInt64) -> (), - completeFunc: (UInt64, UnsafeMutablePointer) -> F, - freeFunc: (UInt64) -> (), - liftFunc: (F) throws -> T, - errorHandler: ((RustBuffer) throws -> Error)? -) async throws -> T { - // Make sure to call uniffiEnsureInitialized() since future creation doesn't have a - // RustCallStatus param, so doesn't use makeRustCall() - uniffiEnsureInitialized() - let rustFuture = rustFutureFunc() - defer { - freeFunc(rustFuture) - } - var pollResult: Int8; - repeat { - pollResult = await withUnsafeContinuation { - pollFunc( - rustFuture, - uniffiFutureContinuationCallback, - uniffiContinuationHandleMap.insert(obj: $0) - ) - } - } while pollResult != UNIFFI_RUST_FUTURE_POLL_READY - - return try liftFunc(makeRustCall( - { completeFunc(rustFuture, $0) }, - errorHandler: errorHandler - )) -} - -// Callback handlers for an async calls. These are invoked by Rust when the future is ready. They -// lift the return value or error and resume the suspended function. -fileprivate func uniffiFutureContinuationCallback(handle: UInt64, pollResult: Int8) { - if let continuation = try? uniffiContinuationHandleMap.remove(handle: handle) { - continuation.resume(returning: pollResult) - } else { - print("uniffiFutureContinuationCallback invalid handle") - } -} - -{%- if ci.has_async_callback_interface_definition() %} -private func uniffiTraitInterfaceCallAsync( - makeCall: @escaping () async throws -> T, - handleSuccess: @escaping (T) -> (), - handleError: @escaping (Int8, RustBuffer) -> () -) -> UniffiForeignFuture { - let task = Task { - do { - handleSuccess(try await makeCall()) - } catch { - handleError(CALL_UNEXPECTED_ERROR, {{ Type::String.borrow()|lower_fn }}(String(describing: error))) - } - } - let handle = UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.insert(obj: task) - return UniffiForeignFuture(handle: handle, free: uniffiForeignFutureFree) - -} - -private func uniffiTraitInterfaceCallAsyncWithError( - makeCall: @escaping () async throws -> T, - handleSuccess: @escaping (T) -> (), - handleError: @escaping (Int8, RustBuffer) -> (), - lowerError: @escaping (E) -> RustBuffer -) -> UniffiForeignFuture { - let task = Task { - do { - handleSuccess(try await makeCall()) - } catch let error as E { - handleError(CALL_ERROR, lowerError(error)) - } catch { - handleError(CALL_UNEXPECTED_ERROR, {{ Type::String.borrow()|lower_fn }}(String(describing: error))) - } - } - let handle = UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.insert(obj: task) - return UniffiForeignFuture(handle: handle, free: uniffiForeignFutureFree) -} - -// Borrow the callback handle map implementation to store foreign future handles -// TODO: consolidate the handle-map code (https://github.com/mozilla/uniffi-rs/pull/1823) -fileprivate var UNIFFI_FOREIGN_FUTURE_HANDLE_MAP = UniffiHandleMap() - -// Protocol for tasks that handle foreign futures. -// -// Defining a protocol allows all tasks to be stored in the same handle map. This can't be done -// with the task object itself, since has generic parameters. -protocol UniffiForeignFutureTask { - func cancel() -} - -extension Task: UniffiForeignFutureTask {} - -private func uniffiForeignFutureFree(handle: UInt64) { - do { - let task = try UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.remove(handle: handle) - // Set the cancellation flag on the task. If it's still running, the code can check the - // cancellation flag or call `Task.checkCancellation()`. If the task has completed, this is - // a no-op. - task.cancel() - } catch { - print("uniffiForeignFutureFree: handle missing from handlemap") - } -} - -// For testing -public func uniffiForeignFutureHandleCount{{ ci.namespace()|class_name }}() -> Int { - UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.count -} - -{%- endif %} +private let UNIFFI_RUST_FUTURE_POLL_READY: Int8 = 0 +private let UNIFFI_RUST_FUTURE_POLL_MAYBE_READY: Int8 = 1 + +fileprivate func uniffiRustCallAsync( + rustFutureFunc: () -> UnsafeMutableRawPointer, + pollFunc: (UnsafeMutableRawPointer, UnsafeMutableRawPointer) -> (), + completeFunc: (UnsafeMutableRawPointer, UnsafeMutablePointer) -> F, + freeFunc: (UnsafeMutableRawPointer) -> (), + liftFunc: (F) throws -> T, + errorHandler: ((RustBuffer) throws -> Error)? +) async throws -> T { + // Make sure to call uniffiEnsureInitialized() since future creation doesn't have a + // RustCallStatus param, so doesn't use makeRustCall() + uniffiEnsureInitialized() + let rustFuture = rustFutureFunc() + defer { + freeFunc(rustFuture) + } + var pollResult: Int8; + repeat { + pollResult = await withUnsafeContinuation { + pollFunc(rustFuture, ContinuationHolder($0).toOpaque()) + } + } while pollResult != UNIFFI_RUST_FUTURE_POLL_READY + + return try liftFunc(makeRustCall( + { completeFunc(rustFuture, $0) }, + errorHandler: errorHandler + )) +} + +// Callback handlers for an async calls. These are invoked by Rust when the future is ready. They +// lift the return value or error and resume the suspended function. +fileprivate func uniffiFutureContinuationCallback(ptr: UnsafeMutableRawPointer, pollResult: Int8) { + ContinuationHolder.fromOpaque(ptr).resume(pollResult) +} + +// Wraps UnsafeContinuation in a class so that we can use reference counting when passing it across +// the FFI +fileprivate class ContinuationHolder { + let continuation: UnsafeContinuation + + init(_ continuation: UnsafeContinuation) { + self.continuation = continuation + } + + func resume(_ pollResult: Int8) { + self.continuation.resume(returning: pollResult) + } + + func toOpaque() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } + + static func fromOpaque(_ ptr: UnsafeRawPointer) -> ContinuationHolder { + return Unmanaged.fromOpaque(ptr).takeRetainedValue() + } +} + +fileprivate func uniffiInitContinuationCallback() { + {{ ci.ffi_rust_future_continuation_callback_set().name() }}(uniffiFutureContinuationCallback) +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/BridgingHeaderTemplate.h b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/BridgingHeaderTemplate.h index 89d98594d399..87698e359fa8 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/BridgingHeaderTemplate.h +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/BridgingHeaderTemplate.h @@ -24,11 +24,25 @@ typedef struct RustBuffer { - uint64_t capacity; - uint64_t len; + int32_t capacity; + int32_t len; uint8_t *_Nullable data; } RustBuffer; +typedef int32_t (*ForeignCallback)(uint64_t, int32_t, const uint8_t *_Nonnull, int32_t, RustBuffer *_Nonnull); + +// Task defined in Rust that Swift executes +typedef void (*UniFfiRustTaskCallback)(const void * _Nullable, int8_t); + +// Callback to execute Rust tasks using a Swift Task +// +// Args: +// executor: ForeignExecutor lowered into a size_t value +// delay: Delay in MS +// task: UniFfiRustTaskCallback to call +// task_data: data to pass the task callback +typedef int8_t (*UniFfiForeignExecutorCallback)(size_t, uint32_t, UniFfiRustTaskCallback _Nullable, const void * _Nullable); + typedef struct ForeignBytes { int32_t len; @@ -45,29 +59,11 @@ typedef struct RustCallStatus { // ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️ #endif // def UNIFFI_SHARED_H -{%- for def in ci.ffi_definitions() %} -#ifndef {{ def.name()|if_guard_name }} -#define {{ def.name()|if_guard_name }} -{%- match def %} -{% when FfiDefinition::CallbackFunction(callback) %} -typedef - {%- match callback.return_type() %}{% when Some(return_type) %} {{ return_type|header_ffi_type_name }} {% when None %} void {% endmatch -%} - (*{{ callback.name()|ffi_callback_name }})( - {%- for arg in callback.arguments() -%} - {{ arg.type_().borrow()|header_ffi_type_name }} - {%- if !loop.last || callback.has_rust_call_status_arg() %}, {% endif %} - {%- endfor -%} - {%- if callback.has_rust_call_status_arg() %} - RustCallStatus *_Nonnull uniffiCallStatus - {%- endif %} - ); -{% when FfiDefinition::Struct(struct) %} -typedef struct {{ struct.name()|ffi_struct_name }} { - {%- for field in struct.fields() %} - {{ field.type_().borrow()|header_ffi_type_name }} {{ field.name()|var_name }}; - {%- endfor %} -} {{ struct.name()|ffi_struct_name }}; -{% when FfiDefinition::Function(func) %} +// Continuation callback for UniFFI Futures +typedef void (*UniFfiRustFutureContinuation)(void * _Nonnull, int8_t); + +// Scaffolding functions +{%- for func in ci.iter_ffi_function_definitions() %} {% match func.return_type() -%}{%- when Some with (type_) %}{{ type_|header_ffi_type_name }}{% when None %}void{% endmatch %} {{ func.name() }}( {%- if func.arguments().len() > 0 %} {%- for arg in func.arguments() %} @@ -78,8 +74,6 @@ typedef struct {{ struct.name()|ffi_struct_name }} { {%- if func.has_rust_call_status_arg() %}RustCallStatus *_Nonnull out_status{%- else %}void{% endif %} {% endif %} ); -{%- endmatch %} -#endif {%- endfor %} {% import "macros.swift" as swift %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceImpl.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceImpl.swift deleted file mode 100644 index 74ee3726422d..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceImpl.swift +++ /dev/null @@ -1,113 +0,0 @@ -{%- if self.include_once_check("CallbackInterfaceRuntime.swift") %}{%- include "CallbackInterfaceRuntime.swift" %}{%- endif %} -{%- let trait_impl=format!("UniffiCallbackInterface{}", name) %} - -// Put the implementation in a struct so we don't pollute the top-level namespace -fileprivate struct {{ trait_impl }} { - - // Create the VTable using a series of closures. - // Swift automatically converts these into C callback functions. - static var vtable: {{ vtable|ffi_type_name }} = {{ vtable|ffi_type_name }}( - {%- for (ffi_callback, meth) in vtable_methods %} - {{ meth.name()|fn_name }}: { ( - {%- for arg in ffi_callback.arguments() %} - {{ arg.name()|var_name }}: {{ arg.type_().borrow()|ffi_type_name }}{% if !loop.last || ffi_callback.has_rust_call_status_arg() %},{% endif %} - {%- endfor -%} - {%- if ffi_callback.has_rust_call_status_arg() %} - uniffiCallStatus: UnsafeMutablePointer - {%- endif %} - ) in - let makeCall = { - () {% if meth.is_async() %}async {% endif %}throws -> {% match meth.return_type() %}{% when Some(t) %}{{ t|type_name }}{% when None %}(){% endmatch %} in - guard let uniffiObj = try? {{ ffi_converter_name }}.handleMap.get(handle: uniffiHandle) else { - throw UniffiInternalError.unexpectedStaleHandle - } - return {% if meth.throws() %}try {% endif %}{% if meth.is_async() %}await {% endif %}uniffiObj.{{ meth.name()|fn_name }}( - {%- for arg in meth.arguments() %} - {% if !config.omit_argument_labels() %} {{ arg.name()|arg_name }}: {% endif %}try {{ arg|lift_fn }}({{ arg.name()|var_name }}){% if !loop.last %},{% endif %} - {%- endfor %} - ) - } - {%- if !meth.is_async() %} - - {% match meth.return_type() %} - {%- when Some(t) %} - let writeReturn = { uniffiOutReturn.pointee = {{ t|lower_fn }}($0) } - {%- when None %} - let writeReturn = { () } - {%- endmatch %} - - {%- match meth.throws_type() %} - {%- when None %} - uniffiTraitInterfaceCall( - callStatus: uniffiCallStatus, - makeCall: makeCall, - writeReturn: writeReturn - ) - {%- when Some(error_type) %} - uniffiTraitInterfaceCallWithError( - callStatus: uniffiCallStatus, - makeCall: makeCall, - writeReturn: writeReturn, - lowerError: {{ error_type|lower_fn }} - ) - {%- endmatch %} - {%- else %} - - let uniffiHandleSuccess = { (returnValue: {{ meth.return_type()|return_type_name }}) in - uniffiFutureCallback( - uniffiCallbackData, - {{ meth.foreign_future_ffi_result_struct().name()|ffi_struct_name }}( - {%- match meth.return_type() %} - {%- when Some(return_type) %} - returnValue: {{ return_type|lower_fn }}(returnValue), - {%- when None %} - {%- endmatch %} - callStatus: RustCallStatus() - ) - ) - } - let uniffiHandleError = { (statusCode, errorBuf) in - uniffiFutureCallback( - uniffiCallbackData, - {{ meth.foreign_future_ffi_result_struct().name()|ffi_struct_name }}( - {%- match meth.return_type() %} - {%- when Some(return_type) %} - returnValue: {{ meth.return_type().map(FfiType::from)|ffi_default_value }}, - {%- when None %} - {%- endmatch %} - callStatus: RustCallStatus(code: statusCode, errorBuf: errorBuf) - ) - ) - } - - {%- match meth.throws_type() %} - {%- when None %} - let uniffiForeignFuture = uniffiTraitInterfaceCallAsync( - makeCall: makeCall, - handleSuccess: uniffiHandleSuccess, - handleError: uniffiHandleError - ) - {%- when Some(error_type) %} - let uniffiForeignFuture = uniffiTraitInterfaceCallAsyncWithError( - makeCall: makeCall, - handleSuccess: uniffiHandleSuccess, - handleError: uniffiHandleError, - lowerError: {{ error_type|lower_fn }} - ) - {%- endmatch %} - uniffiOutReturn.pointee = uniffiForeignFuture - {%- endif %} - }, - {%- endfor %} - uniffiFree: { (uniffiHandle: UInt64) -> () in - let result = try? {{ ffi_converter_name }}.handleMap.remove(handle: uniffiHandle) - if result == nil { - print("Uniffi callback interface {{ name }}: handle missing in uniffiFree") - } - } - ) -} - -private func {{ callback_init }}() { - {{ ffi_init_callback.name() }}(&{{ trait_impl }}.vtable) -} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceRuntime.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceRuntime.swift index 5863c2ad41e1..9ae62d1667e9 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceRuntime.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceRuntime.swift @@ -1,3 +1,60 @@ +fileprivate extension NSLock { + func withLock(f: () throws -> T) rethrows -> T { + self.lock() + defer { self.unlock() } + return try f() + } +} + +fileprivate typealias UniFFICallbackHandle = UInt64 +fileprivate class UniFFICallbackHandleMap { + private var leftMap: [UniFFICallbackHandle: T] = [:] + private var counter: [UniFFICallbackHandle: UInt64] = [:] + private var rightMap: [ObjectIdentifier: UniFFICallbackHandle] = [:] + + private let lock = NSLock() + private var currentHandle: UniFFICallbackHandle = 0 + private let stride: UniFFICallbackHandle = 1 + + func insert(obj: T) -> UniFFICallbackHandle { + lock.withLock { + let id = ObjectIdentifier(obj as AnyObject) + let handle = rightMap[id] ?? { + currentHandle += stride + let handle = currentHandle + leftMap[handle] = obj + rightMap[id] = handle + return handle + }() + counter[handle] = (counter[handle] ?? 0) + 1 + return handle + } + } + + func get(handle: UniFFICallbackHandle) -> T? { + lock.withLock { + leftMap[handle] + } + } + + func delete(handle: UniFFICallbackHandle) { + remove(handle: handle) + } + + @discardableResult + func remove(handle: UniFFICallbackHandle) -> T? { + lock.withLock { + defer { counter[handle] = (counter[handle] ?? 1) - 1 } + guard counter[handle] == 1 else { return leftMap[handle] } + let obj = leftMap.removeValue(forKey: handle) + if let obj = obj { + rightMap.removeValue(forKey: ObjectIdentifier(obj as AnyObject)) + } + return obj + } + } +} + // Magic number for the Rust proxy to call using the same mechanism as every other method, // to free the callback once it's dropped by Rust. private let IDX_CALLBACK_FREE: Int32 = 0 diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceTemplate.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceTemplate.swift index 7aa1cca9b25a..aec8ded930ef 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceTemplate.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/CallbackInterfaceTemplate.swift @@ -1,39 +1,150 @@ {%- let cbi = ci|get_callback_interface_definition(name) %} -{%- let callback_handler = format!("uniffiCallbackHandler{}", name) %} -{%- let callback_init = format!("uniffiCallbackInit{}", name) %} -{%- let methods = cbi.methods() %} -{%- let protocol_name = type_name.clone() %} -{%- let protocol_docstring = cbi.docstring() %} -{%- let vtable = cbi.vtable() %} -{%- let vtable_methods = cbi.vtable_methods() %} -{%- let ffi_init_callback = cbi.ffi_init_callback() %} - -{% include "Protocol.swift" %} -{% include "CallbackInterfaceImpl.swift" %} +{%- let foreign_callback = format!("foreignCallback{}", canonical_type_name) %} +{%- if self.include_once_check("CallbackInterfaceRuntime.swift") %}{%- include "CallbackInterfaceRuntime.swift" %}{%- endif %} + +// Declaration and FfiConverters for {{ type_name }} Callback Interface + +public protocol {{ type_name }} : AnyObject { + {% for meth in cbi.methods() -%} + func {{ meth.name()|fn_name }}({% call swift::arg_list_protocol(meth) %}) {% call swift::throws(meth) -%} + {%- match meth.return_type() -%} + {%- when Some with (return_type) %} -> {{ return_type|type_name -}} + {%- else -%} + {%- endmatch %} + {% endfor %} +} + +// The ForeignCallback that is passed to Rust. +fileprivate let {{ foreign_callback }} : ForeignCallback = + { (handle: UniFFICallbackHandle, method: Int32, argsData: UnsafePointer, argsLen: Int32, out_buf: UnsafeMutablePointer) -> Int32 in + {% for meth in cbi.methods() -%} + {%- let method_name = format!("invoke_{}", meth.name())|fn_name %} + + func {{ method_name }}(_ swiftCallbackInterface: {{ type_name }}, _ argsData: UnsafePointer, _ argsLen: Int32, _ out_buf: UnsafeMutablePointer) throws -> Int32 { + {%- if meth.arguments().len() > 0 %} + var reader = createReader(data: Data(bytes: argsData, count: Int(argsLen))) + {%- endif %} + + {%- match meth.return_type() %} + {%- when Some(return_type) %} + func makeCall() throws -> Int32 { + let result = {% if meth.throws() %} try{% endif %} swiftCallbackInterface.{{ meth.name()|fn_name }}( + {% for arg in meth.arguments() -%} + {% if !config.omit_argument_labels() %}{{ arg.name()|var_name }}: {% endif %} try {{ arg|read_fn }}(from: &reader) + {%- if !loop.last %}, {% endif %} + {% endfor -%} + ) + var writer = [UInt8]() + {{ return_type|write_fn }}(result, into: &writer) + out_buf.pointee = RustBuffer(bytes: writer) + return UNIFFI_CALLBACK_SUCCESS + } + {%- when None %} + func makeCall() throws -> Int32 { + try swiftCallbackInterface.{{ meth.name()|fn_name }}( + {% for arg in meth.arguments() -%} + {% if !config.omit_argument_labels() %}{{ arg.name()|var_name }}: {% endif %} try {{ arg|read_fn }}(from: &reader) + {%- if !loop.last %}, {% endif %} + {% endfor -%} + ) + return UNIFFI_CALLBACK_SUCCESS + } + {%- endmatch %} + + {%- match meth.throws_type() %} + {%- when None %} + return try makeCall() + {%- when Some(error_type) %} + do { + return try makeCall() + } catch let error as {{ error_type|type_name }} { + out_buf.pointee = {{ error_type|lower_fn }}(error) + return UNIFFI_CALLBACK_ERROR + } + {%- endmatch %} + } + {%- endfor %} + + + switch method { + case IDX_CALLBACK_FREE: + {{ ffi_converter_name }}.drop(handle: handle) + // Sucessful return + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + return UNIFFI_CALLBACK_SUCCESS + {% for meth in cbi.methods() -%} + {% let method_name = format!("invoke_{}", meth.name())|fn_name -%} + case {{ loop.index }}: + let cb: {{ cbi|type_name }} + do { + cb = try {{ ffi_converter_name }}.lift(handle) + } catch { + out_buf.pointee = {{ Type::String.borrow()|lower_fn }}("{{ cbi.name() }}: Invalid handle") + return UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + do { + return try {{ method_name }}(cb, argsData, argsLen, out_buf) + } catch let error { + out_buf.pointee = {{ Type::String.borrow()|lower_fn }}(String(describing: error)) + return UNIFFI_CALLBACK_UNEXPECTED_ERROR + } + {% endfor %} + // This should never happen, because an out of bounds method index won't + // ever be used. Once we can catch errors, we should return an InternalError. + // https://github.com/mozilla/uniffi-rs/issues/351 + default: + // An unexpected error happened. + // See docs of ForeignCallback in `uniffi_core/src/ffi/foreigncallbacks.rs` + return UNIFFI_CALLBACK_UNEXPECTED_ERROR + } +} // FfiConverter protocol for callback interfaces fileprivate struct {{ ffi_converter_name }} { - fileprivate static var handleMap = UniffiHandleMap<{{ type_name }}>() + private static let initCallbackOnce: () = { + // Swift ensures this initializer code will once run once, even when accessed by multiple threads. + try! rustCall { (err: UnsafeMutablePointer) in + {{ cbi.ffi_init_callback().name() }}({{ foreign_callback }}, err) + } + }() + + private static func ensureCallbackinitialized() { + _ = initCallbackOnce + } + + static func drop(handle: UniFFICallbackHandle) { + handleMap.remove(handle: handle) + } + + private static var handleMap = UniFFICallbackHandleMap<{{ type_name }}>() } extension {{ ffi_converter_name }} : FfiConverter { typealias SwiftType = {{ type_name }} - typealias FfiType = UInt64 + // We can use Handle as the FfiType because it's a typealias to UInt64 + typealias FfiType = UniFFICallbackHandle - public static func lift(_ handle: UInt64) throws -> SwiftType { - try handleMap.get(handle: handle) + public static func lift(_ handle: UniFFICallbackHandle) throws -> SwiftType { + ensureCallbackinitialized(); + guard let callback = handleMap.get(handle: handle) else { + throw UniffiInternalError.unexpectedStaleHandle + } + return callback } public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { - let handle: UInt64 = try readInt(&buf) + ensureCallbackinitialized(); + let handle: UniFFICallbackHandle = try readInt(&buf) return try lift(handle) } - public static func lower(_ v: SwiftType) -> UInt64 { + public static func lower(_ v: SwiftType) -> UniFFICallbackHandle { + ensureCallbackinitialized(); return handleMap.insert(obj: v) } public static func write(_ v: SwiftType, into buf: inout [UInt8]) { + ensureCallbackinitialized(); writeInt(&buf, lower(v)) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/EnumTemplate.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/EnumTemplate.swift index 1d8b3cf500f4..99f45290cc66 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/EnumTemplate.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/EnumTemplate.swift @@ -1,26 +1,10 @@ // Note that we don't yet support `indirect` for enums. // See https://github.com/mozilla/uniffi-rs/issues/396 for further discussion. -{%- call swift::docstring(e, 0) %} -{% match e.variant_discr_type() %} -{% when None %} public enum {{ type_name }} { {% for variant in e.variants() %} - {%- call swift::docstring(variant, 4) %} - case {{ variant.name()|enum_variant_swift_quoted }}{% if variant.fields().len() > 0 %}( - {%- call swift::field_list_decl(variant, variant.has_nameless_fields()) %} - ){% endif -%} + case {{ variant.name()|enum_variant_swift_quoted }}{% if variant.fields().len() > 0 %}({% call swift::field_list_decl(variant) %}){% endif -%} {% endfor %} } -{% when Some with (variant_discr_type) %} -public enum {{ type_name }} : {{ variant_discr_type|type_name }} { - {% for variant in e.variants() %} - {%- call swift::docstring(variant, 4) %} - case {{ variant.name()|enum_variant_swift_quoted }} = {{ e|variant_discr_literal(loop.index0) }}{% if variant.fields().len() > 0 %}( - {%- call swift::field_list_decl(variant, variant.has_nameless_fields()) %} - ){% endif -%} - {% endfor %} -} -{% endmatch %} public struct {{ ffi_converter_name }}: FfiConverterRustBuffer { typealias SwiftType = {{ type_name }} @@ -31,11 +15,7 @@ public struct {{ ffi_converter_name }}: FfiConverterRustBuffer { {% for variant in e.variants() %} case {{ loop.index }}: return .{{ variant.name()|enum_variant_swift_quoted }}{% if variant.has_fields() %}( {%- for field in variant.fields() %} - {%- if variant.has_nameless_fields() -%} - try {{ field|read_fn }}(from: &buf) - {%- else -%} {{ field.name()|arg_name }}: try {{ field|read_fn }}(from: &buf) - {%- endif -%} {%- if !loop.last %}, {% endif %} {%- endfor %} ){%- endif %} @@ -48,10 +28,10 @@ public struct {{ ffi_converter_name }}: FfiConverterRustBuffer { switch value { {% for variant in e.variants() %} {% if variant.has_fields() %} - case let .{{ variant.name()|enum_variant_swift_quoted }}({% for field in variant.fields() %}{%- call swift::field_name(field, loop.index) -%}{%- if loop.last -%}{%- else -%},{%- endif -%}{% endfor %}): + case let .{{ variant.name()|enum_variant_swift_quoted }}({% for field in variant.fields() %}{{ field.name()|var_name }}{%- if loop.last -%}{%- else -%},{%- endif -%}{% endfor %}): writeInt(&buf, Int32({{ loop.index }})) {% for field in variant.fields() -%} - {{ field|write_fn }}({% call swift::field_name(field, loop.index) %}, into: &buf) + {{ field|write_fn }}({{ field.name()|var_name }}, into: &buf) {% endfor -%} {% else %} case .{{ variant.name()|enum_variant_swift_quoted }}: @@ -75,6 +55,5 @@ public func {{ ffi_converter_name }}_lower(_ value: {{ type_name }}) -> RustBuff } {% if !contains_object_references %} -{% if config.experimental_sendable_value_types() %}extension {{ type_name }}: Sendable {} {% endif %} extension {{ type_name }}: Equatable, Hashable {} {% endif %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ErrorTemplate.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ErrorTemplate.swift index 0702c477e940..786091395bcd 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ErrorTemplate.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ErrorTemplate.swift @@ -1,21 +1,21 @@ -{%- call swift::docstring(e, 0) %} public enum {{ type_name }} { {% if e.is_flat() %} {% for variant in e.variants() %} - {%- call swift::docstring(variant, 4) %} + // Simple error enums only carry a message case {{ variant.name()|class_name }}(message: String) {% endfor %} {%- else %} {% for variant in e.variants() %} - {%- call swift::docstring(variant, 4) %} - case {{ variant.name()|class_name }}{% if variant.fields().len() > 0 %}( - {%- call swift::field_list_decl(variant, variant.has_nameless_fields()) %} - ){% endif -%} + case {{ variant.name()|class_name }}{% if variant.fields().len() > 0 %}({% call swift::field_list_decl(variant) %}){% endif -%} {% endfor %} {%- endif %} + + fileprivate static func uniffiErrorHandler(_ error: RustBuffer) throws -> Error { + return try {{ ffi_converter_name }}.lift(error) + } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ForeignExecutorTemplate.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ForeignExecutorTemplate.swift new file mode 100644 index 000000000000..167e4c754605 --- /dev/null +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ForeignExecutorTemplate.swift @@ -0,0 +1,69 @@ +private let UNIFFI_RUST_TASK_CALLBACK_SUCCESS: Int8 = 0 +private let UNIFFI_RUST_TASK_CALLBACK_CANCELLED: Int8 = 1 +private let UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS: Int8 = 0 +private let UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELED: Int8 = 1 +private let UNIFFI_FOREIGN_EXECUTOR_CALLBACK_ERROR: Int8 = 2 + +// Encapsulates an executor that can run Rust tasks +// +// On Swift, `Task.detached` can handle this we just need to know what priority to send it. +public struct UniFfiForeignExecutor { + var priority: TaskPriority + + public init(priority: TaskPriority) { + self.priority = priority + } + + public init() { + self.priority = Task.currentPriority + } +} + +fileprivate struct FfiConverterForeignExecutor: FfiConverter { + typealias SwiftType = UniFfiForeignExecutor + // Rust uses a pointer to represent the FfiConverterForeignExecutor, but we only need a u8. + // let's use `Int`, which is equivalent to `size_t` + typealias FfiType = Int + + public static func lift(_ value: FfiType) throws -> SwiftType { + UniFfiForeignExecutor(priority: TaskPriority(rawValue: numericCast(value))) + } + public static func lower(_ value: SwiftType) -> FfiType { + numericCast(value.priority.rawValue) + } + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> SwiftType { + fatalError("FfiConverterForeignExecutor.read not implemented yet") + } + public static func write(_ value: SwiftType, into buf: inout [UInt8]) { + fatalError("FfiConverterForeignExecutor.read not implemented yet") + } +} + + +fileprivate func uniffiForeignExecutorCallback(executorHandle: Int, delayMs: UInt32, rustTask: UniFfiRustTaskCallback?, taskData: UnsafeRawPointer?) -> Int8 { + if let rustTask = rustTask { + let executor = try! FfiConverterForeignExecutor.lift(executorHandle) + Task.detached(priority: executor.priority) { + if delayMs != 0 { + let nanoseconds: UInt64 = numericCast(delayMs * 1000000) + try! await Task.sleep(nanoseconds: nanoseconds) + } + rustTask(taskData, UNIFFI_RUST_TASK_CALLBACK_SUCCESS) + } + return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS + } else { + // When rustTask is null, we should drop the foreign executor. + // However, since its just a value type, we don't need to do anything here. + return UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS + } +} + +fileprivate func uniffiInitForeignExecutor() { + {%- match ci.ffi_foreign_executor_callback_set() %} + {%- when Some with (fn) %} + {{ fn.name() }}(uniffiForeignExecutorCallback) + {%- when None %} + {#- No foreign executor, we don't set anything #} + {% endmatch %} +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/HandleMap.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/HandleMap.swift deleted file mode 100644 index 6de9f085d616..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/HandleMap.swift +++ /dev/null @@ -1,40 +0,0 @@ -fileprivate class UniffiHandleMap { - private var map: [UInt64: T] = [:] - private let lock = NSLock() - private var currentHandle: UInt64 = 1 - - func insert(obj: T) -> UInt64 { - lock.withLock { - let handle = currentHandle - currentHandle += 1 - map[handle] = obj - return handle - } - } - - func get(handle: UInt64) throws -> T { - try lock.withLock { - guard let obj = map[handle] else { - throw UniffiInternalError.unexpectedStaleHandle - } - return obj - } - } - - @discardableResult - func remove(handle: UInt64) throws -> T { - try lock.withLock { - guard let obj = map.removeValue(forKey: handle) else { - throw UniffiInternalError.unexpectedStaleHandle - } - return obj - } - } - - var count: Int { - get { - map.count - } - } -} - diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Helpers.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Helpers.swift index cfddf7b3139f..a34b128e2363 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Helpers.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Helpers.swift @@ -26,17 +26,9 @@ fileprivate enum UniffiInternalError: LocalizedError { } } -fileprivate extension NSLock { - func withLock(f: () throws -> T) rethrows -> T { - self.lock() - defer { self.unlock() } - return try f() - } -} - fileprivate let CALL_SUCCESS: Int8 = 0 fileprivate let CALL_ERROR: Int8 = 1 -fileprivate let CALL_UNEXPECTED_ERROR: Int8 = 2 +fileprivate let CALL_PANIC: Int8 = 2 fileprivate let CALL_CANCELLED: Int8 = 3 fileprivate extension RustCallStatus { @@ -89,7 +81,7 @@ private func uniffiCheckCallStatus( throw UniffiInternalError.unexpectedRustCallError } - case CALL_UNEXPECTED_ERROR: + case CALL_PANIC: // When the rust code sees a panic, it tries to construct a RustBuffer // with the message. But if that code panics, then it just sends back // an empty buffer. @@ -101,39 +93,9 @@ private func uniffiCheckCallStatus( } case CALL_CANCELLED: - fatalError("Cancellation not supported yet") + throw CancellationError() default: throw UniffiInternalError.unexpectedRustCallStatusCode } } - -private func uniffiTraitInterfaceCall( - callStatus: UnsafeMutablePointer, - makeCall: () throws -> T, - writeReturn: (T) -> () -) { - do { - try writeReturn(makeCall()) - } catch let error { - callStatus.pointee.code = CALL_UNEXPECTED_ERROR - callStatus.pointee.errorBuf = {{ Type::String.borrow()|lower_fn }}(String(describing: error)) - } -} - -private func uniffiTraitInterfaceCallWithError( - callStatus: UnsafeMutablePointer, - makeCall: () throws -> T, - writeReturn: (T) -> (), - lowerError: (E) -> RustBuffer -) { - do { - try writeReturn(makeCall()) - } catch let error as E { - callStatus.pointee.code = CALL_ERROR - callStatus.pointee.errorBuf = lowerError(error) - } catch { - callStatus.pointee.code = CALL_UNEXPECTED_ERROR - callStatus.pointee.errorBuf = {{ Type::String.borrow()|lower_fn }}(String(describing: error)) - } -} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ObjectTemplate.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ObjectTemplate.swift dissimilarity index 68% index 0c28bc4c0959..57a77ca6dfce 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ObjectTemplate.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/ObjectTemplate.swift @@ -1,195 +1,138 @@ -{%- let obj = ci|get_object_definition(name) %} -{%- let (protocol_name, impl_class_name) = obj|object_names %} -{%- let methods = obj.methods() %} -{%- let protocol_docstring = obj.docstring() %} - -{%- let is_error = ci.is_name_used_as_error(name) %} - -{% include "Protocol.swift" %} - -{%- call swift::docstring(obj, 0) %} -open class {{ impl_class_name }}: - {%- for tm in obj.uniffi_traits() %} - {%- match tm %} - {%- when UniffiTrait::Display { fmt } %} - CustomStringConvertible, - {%- when UniffiTrait::Debug { fmt } %} - CustomDebugStringConvertible, - {%- when UniffiTrait::Eq { eq, ne } %} - Equatable, - {%- when UniffiTrait::Hash { hash } %} - Hashable, - {%- else %} - {%- endmatch %} - {%- endfor %} - {%- if is_error %} - Error, - {% endif %} - {{ protocol_name }} { - fileprivate let pointer: UnsafeMutableRawPointer! - - /// Used to instantiate a [FFIObject] without an actual pointer, for fakes in tests, mostly. - public struct NoPointer { - public init() {} - } - - // TODO: We'd like this to be `private` but for Swifty reasons, - // we can't implement `FfiConverter` without making this `required` and we can't - // make it `required` without making it `public`. - required public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { - self.pointer = pointer - } - - /// This constructor can be used to instantiate a fake object. - /// - Parameter noPointer: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject]. - /// - /// - Warning: - /// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing [Pointer] the FFI lower functions will crash. - public init(noPointer: NoPointer) { - self.pointer = nil - } - - public func uniffiClonePointer() -> UnsafeMutableRawPointer { - return try! rustCall { {{ obj.ffi_object_clone().name() }}(self.pointer, $0) } - } - - {%- match obj.primary_constructor() %} - {%- when Some with (cons) %} - {%- call swift::ctor_decl(cons, 4) %} - {%- when None %} - // No primary constructor declared for this class. - {%- endmatch %} - - deinit { - guard let pointer = pointer else { - return - } - - try! rustCall { {{ obj.ffi_object_free().name() }}(pointer, $0) } - } - - {% for cons in obj.alternate_constructors() %} - {%- call swift::func_decl("public static func", cons, 4) %} - {% endfor %} - - {% for meth in obj.methods() -%} - {%- call swift::func_decl("open func", meth, 4) %} - {% endfor %} - - {%- for tm in obj.uniffi_traits() %} - {%- match tm %} - {%- when UniffiTrait::Display { fmt } %} - open var description: String { - return {% call swift::try(fmt) %} {{ fmt.return_type().unwrap()|lift_fn }}( - {% call swift::to_ffi_call(fmt) %} - ) - } - {%- when UniffiTrait::Debug { fmt } %} - open var debugDescription: String { - return {% call swift::try(fmt) %} {{ fmt.return_type().unwrap()|lift_fn }}( - {% call swift::to_ffi_call(fmt) %} - ) - } - {%- when UniffiTrait::Eq { eq, ne } %} - public static func == (self: {{ impl_class_name }}, other: {{ impl_class_name }}) -> Bool { - return {% call swift::try(eq) %} {{ eq.return_type().unwrap()|lift_fn }}( - {% call swift::to_ffi_call(eq) %} - ) - } - {%- when UniffiTrait::Hash { hash } %} - open func hash(into hasher: inout Hasher) { - let val = {% call swift::try(hash) %} {{ hash.return_type().unwrap()|lift_fn }}( - {% call swift::to_ffi_call(hash) %} - ) - hasher.combine(val) - } - {%- else %} - {%- endmatch %} - {%- endfor %} - -} - -{%- if obj.has_callback_interface() %} -{%- let callback_handler = format!("uniffiCallbackInterface{}", name) %} -{%- let callback_init = format!("uniffiCallbackInit{}", name) %} -{%- let vtable = obj.vtable().expect("trait interface should have a vtable") %} -{%- let vtable_methods = obj.vtable_methods() %} -{%- let ffi_init_callback = obj.ffi_init_callback() %} -{% include "CallbackInterfaceImpl.swift" %} -{%- endif %} - -public struct {{ ffi_converter_name }}: FfiConverter { - {%- if obj.has_callback_interface() %} - fileprivate static var handleMap = UniffiHandleMap<{{ type_name }}>() - {%- endif %} - - typealias FfiType = UnsafeMutableRawPointer - typealias SwiftType = {{ type_name }} - - public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> {{ type_name }} { - return {{ impl_class_name }}(unsafeFromRawPointer: pointer) - } - - public static func lower(_ value: {{ type_name }}) -> UnsafeMutableRawPointer { - {%- if obj.has_callback_interface() %} - guard let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: handleMap.insert(obj: value))) else { - fatalError("Cast to UnsafeMutableRawPointer failed") - } - return ptr - {%- else %} - return value.uniffiClonePointer() - {%- endif %} - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> {{ type_name }} { - let v: UInt64 = try readInt(&buf) - // The Rust code won't compile if a pointer won't fit in a UInt64. - // We have to go via `UInt` because that's the thing that's the size of a pointer. - let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) - if (ptr == nil) { - throw UniffiInternalError.unexpectedNullPointer - } - return try lift(ptr!) - } - - public static func write(_ value: {{ type_name }}, into buf: inout [UInt8]) { - // This fiddling is because `Int` is the thing that's the same size as a pointer. - // The Rust code won't compile if a pointer won't fit in a `UInt64`. - writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) - } -} - -{# Objects as error #} -{%- if is_error %} -{# Due to some mismatches in the ffi converter mechanisms, errors are a RustBuffer holding a pointer #} -public struct {{ ffi_converter_name }}__as_error: FfiConverterRustBuffer { - public static func lift(_ buf: RustBuffer) throws -> {{ type_name }} { - var reader = createReader(data: Data(rustBuffer: buf)) - return try {{ ffi_converter_name }}.read(from: &reader) - } - - public static func lower(_ value: {{ type_name }}) -> RustBuffer { - fatalError("not implemented") - } - - public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> {{ type_name }} { - fatalError("not implemented") - } - - public static func write(_ value: {{ type_name }}, into buf: inout [UInt8]) { - fatalError("not implemented") - } -} -{%- endif %} - -{# -We always write these public functions just in case the enum is used as -an external type by another crate. -#} -public func {{ ffi_converter_name }}_lift(_ pointer: UnsafeMutableRawPointer) throws -> {{ type_name }} { - return try {{ ffi_converter_name }}.lift(pointer) -} - -public func {{ ffi_converter_name }}_lower(_ value: {{ type_name }}) -> UnsafeMutableRawPointer { - return {{ ffi_converter_name }}.lower(value) -} +{%- let obj = ci|get_object_definition(name) %} +public protocol {{ obj.name() }}Protocol { + {% for meth in obj.methods() -%} + func {{ meth.name()|fn_name }}({% call swift::arg_list_protocol(meth) %}) {% call swift::async(meth) %} {% call swift::throws(meth) -%} + {%- match meth.return_type() -%} + {%- when Some with (return_type) %} -> {{ return_type|type_name -}} + {%- else -%} + {%- endmatch %} + {% endfor %} +} + +public class {{ type_name }}: {{ obj.name() }}Protocol { + fileprivate let pointer: UnsafeMutableRawPointer + + // TODO: We'd like this to be `private` but for Swifty reasons, + // we can't implement `FfiConverter` without making this `required` and we can't + // make it `required` without making it `public`. + required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + self.pointer = pointer + } + + {%- match obj.primary_constructor() %} + {%- when Some with (cons) %} + public convenience init({% call swift::arg_list_decl(cons) -%}) {% call swift::throws(cons) %} { + self.init(unsafeFromRawPointer: {% call swift::to_ffi_call(cons) %}) + } + {%- when None %} + {%- endmatch %} + + deinit { + try! rustCall { {{ obj.ffi_object_free().name() }}(pointer, $0) } + } + + {% for cons in obj.alternate_constructors() %} + + public static func {{ cons.name()|fn_name }}({% call swift::arg_list_decl(cons) %}) {% call swift::throws(cons) %} -> {{ type_name }} { + return {{ type_name }}(unsafeFromRawPointer: {% call swift::to_ffi_call(cons) %}) + } + + {% endfor %} + + {# // TODO: Maybe merge the two templates (i.e the one with a return type and the one without) #} + {% for meth in obj.methods() -%} + {%- if meth.is_async() %} + + public func {{ meth.name()|fn_name }}({%- call swift::arg_list_decl(meth) -%}) async {% call swift::throws(meth) %}{% match meth.return_type() %}{% when Some with (return_type) %} -> {{ return_type|type_name }}{% when None %}{% endmatch %} { + return {% call swift::try(meth) %} await uniffiRustCallAsync( + rustFutureFunc: { + {{ meth.ffi_func().name() }}( + self.pointer + {%- for arg in meth.arguments() -%} + , + {{ arg|lower_fn }}({{ arg.name()|var_name }}) + {%- endfor %} + ) + }, + pollFunc: {{ meth.ffi_rust_future_poll(ci) }}, + completeFunc: {{ meth.ffi_rust_future_complete(ci) }}, + freeFunc: {{ meth.ffi_rust_future_free(ci) }}, + {%- match meth.return_type() %} + {%- when Some(return_type) %} + liftFunc: {{ return_type|lift_fn }}, + {%- when None %} + liftFunc: { $0 }, + {%- endmatch %} + {%- match meth.throws_type() %} + {%- when Some with (e) %} + errorHandler: {{ e|ffi_converter_name }}.lift + {%- else %} + errorHandler: nil + {% endmatch %} + ) + } + + {% else -%} + + {%- match meth.return_type() -%} + + {%- when Some with (return_type) %} + + public func {{ meth.name()|fn_name }}({% call swift::arg_list_decl(meth) %}) {% call swift::throws(meth) %} -> {{ return_type|type_name }} { + return {% call swift::try(meth) %} {{ return_type|lift_fn }}( + {% call swift::to_ffi_call_with_prefix("self.pointer", meth) %} + ) + } + + {%- when None %} + + public func {{ meth.name()|fn_name }}({% call swift::arg_list_decl(meth) %}) {% call swift::throws(meth) %} { + {% call swift::to_ffi_call_with_prefix("self.pointer", meth) %} + } + + {%- endmatch -%} + {%- endif -%} + {% endfor %} +} + +public struct {{ ffi_converter_name }}: FfiConverter { + typealias FfiType = UnsafeMutableRawPointer + typealias SwiftType = {{ type_name }} + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> {{ type_name }} { + let v: UInt64 = try readInt(&buf) + // The Rust code won't compile if a pointer won't fit in a UInt64. + // We have to go via `UInt` because that's the thing that's the size of a pointer. + let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v)) + if (ptr == nil) { + throw UniffiInternalError.unexpectedNullPointer + } + return try lift(ptr!) + } + + public static func write(_ value: {{ type_name }}, into buf: inout [UInt8]) { + // This fiddling is because `Int` is the thing that's the same size as a pointer. + // The Rust code won't compile if a pointer won't fit in a `UInt64`. + writeInt(&buf, UInt64(bitPattern: Int64(Int(bitPattern: lower(value))))) + } + + public static func lift(_ pointer: UnsafeMutableRawPointer) throws -> {{ type_name }} { + return {{ type_name}}(unsafeFromRawPointer: pointer) + } + + public static func lower(_ value: {{ type_name }}) -> UnsafeMutableRawPointer { + return value.pointer + } +} + +{# +We always write these public functions just in case the enum is used as +an external type by another crate. +#} +public func {{ ffi_converter_name }}_lift(_ pointer: UnsafeMutableRawPointer) throws -> {{ type_name }} { + return try {{ ffi_converter_name }}.lift(pointer) +} + +public func {{ ffi_converter_name }}_lower(_ value: {{ type_name }}) -> UnsafeMutableRawPointer { + return {{ ffi_converter_name }}.lower(value) +} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Protocol.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Protocol.swift deleted file mode 100644 index 7df953558aa2..000000000000 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Protocol.swift +++ /dev/null @@ -1,12 +0,0 @@ -{%- call swift::docstring_value(protocol_docstring, 0) %} -public protocol {{ protocol_name }} : AnyObject { - {% for meth in methods.iter() -%} - {%- call swift::docstring(meth, 4) %} - func {{ meth.name()|fn_name }}({% call swift::arg_list_protocol(meth) %}) {% call swift::async(meth) -%}{% call swift::throws(meth) -%} - {%- match meth.return_type() -%} - {%- when Some with (return_type) %} -> {{ return_type|type_name -}} - {%- else -%} - {%- endmatch %} - {% endfor %} -} - diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/RecordTemplate.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/RecordTemplate.swift index c262a7a2166f..44de9dd358bd 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/RecordTemplate.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/RecordTemplate.swift @@ -1,14 +1,12 @@ {%- let rec = ci|get_record_definition(name) %} -{%- call swift::docstring(rec, 0) %} public struct {{ type_name }} { {%- for field in rec.fields() %} - {%- call swift::docstring(field, 4) %} - public {% if config.generate_immutable_records() %}let{% else %}var{% endif %} {{ field.name()|var_name }}: {{ field|type_name }} + public var {{ field.name()|var_name }}: {{ field|type_name }} {%- endfor %} // Default memberwise initializers are never public by default, so we // declare one manually. - public init({% call swift::field_list_decl(rec, false) %}) { + public init({% call swift::field_list_decl(rec) %}) { {%- for field in rec.fields() %} self.{{ field.name()|var_name }} = {{ field.name()|var_name }} {%- endfor %} @@ -16,7 +14,6 @@ public struct {{ type_name }} { } {% if !contains_object_references %} -{% if config.experimental_sendable_value_types() %}extension {{ type_name }}: Sendable {} {% endif %} extension {{ type_name }}: Equatable, Hashable { public static func ==(lhs: {{ type_name }}, rhs: {{ type_name }}) -> Bool { {%- for field in rec.fields() %} @@ -37,16 +34,12 @@ extension {{ type_name }}: Equatable, Hashable { public struct {{ ffi_converter_name }}: FfiConverterRustBuffer { public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> {{ type_name }} { - return {%- if rec.has_fields() %} - try {{ type_name }}( + return try {{ type_name }}( {%- for field in rec.fields() %} - {{ field.name()|arg_name }}: {{ field|read_fn }}(from: &buf) - {%- if !loop.last %}, {% endif %} + {{ field.name()|arg_name }}: {{ field|read_fn }}(from: &buf) + {%- if !loop.last %}, {% endif %} {%- endfor %} ) - {%- else %} - {{ type_name }}() - {%- endif %} } public static func write(_ value: {{ type_name }}, into buf: inout [UInt8]) { diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/RustBufferTemplate.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/RustBufferTemplate.swift index a053334a3022..2f737b663514 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/RustBufferTemplate.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/RustBufferTemplate.swift @@ -7,10 +7,6 @@ fileprivate extension RustBuffer { self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data) } - static func empty() -> RustBuffer { - RustBuffer(capacity: 0, len:0, data: nil) - } - static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer { try! rustCall { {{ ci.ffi_rustbuffer_from_bytes().name() }}(ForeignBytes(bufferPointer: ptr), $0) } } diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/TopLevelFunctionTemplate.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/TopLevelFunctionTemplate.swift dissimilarity index 100% index ce946076f701..a2c6311931e4 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/TopLevelFunctionTemplate.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/TopLevelFunctionTemplate.swift @@ -1 +1,48 @@ -{%- call swift::func_decl("public func", func, 0) %} +{%- if func.is_async() %} + +public func {{ func.name()|fn_name }}({%- call swift::arg_list_decl(func) -%}) async {% call swift::throws(func) %}{% match func.return_type() %}{% when Some with (return_type) %} -> {{ return_type|type_name }}{% when None %}{% endmatch %} { + return {% call swift::try(func) %} await uniffiRustCallAsync( + rustFutureFunc: { + {{ func.ffi_func().name() }}( + {%- for arg in func.arguments() %} + {{ arg|lower_fn }}({{ arg.name()|var_name }}){% if !loop.last %},{% endif %} + {%- endfor %} + ) + }, + pollFunc: {{ func.ffi_rust_future_poll(ci) }}, + completeFunc: {{ func.ffi_rust_future_complete(ci) }}, + freeFunc: {{ func.ffi_rust_future_free(ci) }}, + {%- match func.return_type() %} + {%- when Some(return_type) %} + liftFunc: {{ return_type|lift_fn }}, + {%- when None %} + liftFunc: { $0 }, + {%- endmatch %} + {%- match func.throws_type() %} + {%- when Some with (e) %} + errorHandler: {{ e|ffi_converter_name }}.lift + {%- else %} + errorHandler: nil + {% endmatch %} + ) +} + +{% else %} + +{%- match func.return_type() -%} +{%- when Some with (return_type) %} + +public func {{ func.name()|fn_name }}({%- call swift::arg_list_decl(func) -%}) {% call swift::throws(func) %} -> {{ return_type|type_name }} { + return {% call swift::try(func) %} {{ return_type|lift_fn }}( + {% call swift::to_ffi_call(func) %} + ) +} + +{%- when None %} + +public func {{ func.name()|fn_name }}({% call swift::arg_list_decl(func) %}) {% call swift::throws(func) %} { + {% call swift::to_ffi_call(func) %} +} + +{% endmatch %} +{%- endif %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Types.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Types.swift index 5e26758f3c35..aba34f4b0bd4 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Types.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Types.swift @@ -64,6 +64,9 @@ {%- when Type::CallbackInterface { name, module_path } %} {%- include "CallbackInterfaceTemplate.swift" %} +{%- when Type::ForeignExecutor %} +{%- include "ForeignExecutorTemplate.swift" %} + {%- when Type::Custom { name, module_path, builtin } %} {%- include "CustomType.swift" %} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/macros.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/macros.swift dissimilarity index 65% index 8692cd6ff071..0a125e6f619a 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/macros.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/macros.swift @@ -1,182 +1,89 @@ -{# -// Template to call into rust. Used in several places. -// Variable names in `arg_list_decl` should match up with arg lists -// passed to rust via `arg_list_lowered` -#} - -{%- macro to_ffi_call(func) -%} - {%- call try(func) -%} - {%- match func.throws_type() -%} - {%- when Some with (e) -%} - rustCallWithError({{ e|ffi_error_converter_name }}.lift) { - {%- else -%} - rustCall() { - {%- endmatch %} - {{ func.ffi_func().name() }}( - {%- if func.takes_self() %}self.uniffiClonePointer(),{% endif %} - {%- call arg_list_lowered(func) -%} $0 - ) -} -{%- endmacro -%} - -// eg, `public func foo_bar() { body }` -{%- macro func_decl(func_decl, callable, indent) %} -{%- call docstring(callable, indent) %} -{{ func_decl }} {{ callable.name()|fn_name }}( - {%- call arg_list_decl(callable) -%}) - {%- call async(callable) %} - {%- call throws(callable) %} - {%- match callable.return_type() %} - {%- when Some with (return_type) %} -> {{ return_type|type_name }} - {%- when None %} - {%- endmatch %} { - {%- call call_body(callable) %} -} -{%- endmacro %} - -// primary ctor - no name, no return-type. -{%- macro ctor_decl(callable, indent) %} -{%- call docstring(callable, indent) %} -public convenience init( - {%- call arg_list_decl(callable) -%}) {%- call async(callable) %} {%- call throws(callable) %} { - {%- if callable.is_async() %} - let pointer = - {%- call call_async(callable) %} - {# The async mechanism returns an already constructed self. - We work around that by cloning the pointer from that object, then - assune the old object dies as there are no other references possible. - #} - .uniffiClonePointer() - {%- else %} - let pointer = - {% call to_ffi_call(callable) %} - {%- endif %} - self.init(unsafeFromRawPointer: pointer) -} -{%- endmacro %} - -{%- macro call_body(callable) %} -{%- if callable.is_async() %} - return {%- call call_async(callable) %} -{%- else %} -{%- match callable.return_type() -%} -{%- when Some with (return_type) %} - return {% call try(callable) %} {{ return_type|lift_fn }}({% call to_ffi_call(callable) %}) -{%- when None %} -{%- call to_ffi_call(callable) %} -{%- endmatch %} -{%- endif %} - -{%- endmacro %} - -{%- macro call_async(callable) %} - {% call try(callable) %} await uniffiRustCallAsync( - rustFutureFunc: { - {{ callable.ffi_func().name() }}( - {%- if callable.takes_self() %} - self.uniffiClonePointer(){% if !callable.arguments().is_empty() %},{% endif %} - {% endif %} - {%- for arg in callable.arguments() -%} - {{ arg|lower_fn }}({{ arg.name()|var_name }}){% if !loop.last %},{% endif %} - {%- endfor %} - ) - }, - pollFunc: {{ callable.ffi_rust_future_poll(ci) }}, - completeFunc: {{ callable.ffi_rust_future_complete(ci) }}, - freeFunc: {{ callable.ffi_rust_future_free(ci) }}, - {%- match callable.return_type() %} - {%- when Some(return_type) %} - liftFunc: {{ return_type|lift_fn }}, - {%- when None %} - liftFunc: { $0 }, - {%- endmatch %} - {%- match callable.throws_type() %} - {%- when Some with (e) %} - errorHandler: {{ e|ffi_error_converter_name }}.lift - {%- else %} - errorHandler: nil - {% endmatch %} - ) -{%- endmacro %} - -{%- macro arg_list_lowered(func) %} - {%- for arg in func.arguments() %} - {{ arg|lower_fn }}({{ arg.name()|var_name }}), - {%- endfor %} -{%- endmacro -%} - -{#- -// Arglist as used in Swift declarations of methods, functions and constructors. -// Note the var_name and type_name filters. --#} - -{% macro arg_list_decl(func) %} - {%- for arg in func.arguments() -%} - {% if config.omit_argument_labels() %}_ {% endif %}{{ arg.name()|var_name }}: {{ arg|type_name -}} - {%- match arg.default_value() %} - {%- when Some with(literal) %} = {{ literal|literal_swift(arg) }} - {%- else %} - {%- endmatch %} - {%- if !loop.last %}, {% endif -%} - {%- endfor %} -{%- endmacro %} - -{#- -// Field lists as used in Swift declarations of Records and Enums. -// Note the var_name and type_name filters. --#} -{% macro field_list_decl(item, has_nameless_fields) %} - {%- for field in item.fields() -%} - {%- call docstring(field, 8) %} - {%- if has_nameless_fields %} - {{- field|type_name -}} - {%- if !loop.last -%}, {%- endif -%} - {%- else -%} - {{ field.name()|var_name }}: {{ field|type_name -}} - {%- match field.default_value() %} - {%- when Some with(literal) %} = {{ literal|literal_swift(field) }} - {%- else %} - {%- endmatch -%} - {% if !loop.last %}, {% endif %} - {%- endif -%} - {%- endfor %} -{%- endmacro %} - -{% macro field_name(field, field_num) %} -{%- if field.name().is_empty() -%} -v{{- field_num -}} -{%- else -%} -{{ field.name()|var_name }} -{%- endif -%} -{%- endmacro %} - -{% macro arg_list_protocol(func) %} - {%- for arg in func.arguments() -%} - {% if config.omit_argument_labels() %}_ {% endif %}{{ arg.name()|var_name }}: {{ arg|type_name -}} - {%- if !loop.last %}, {% endif -%} - {%- endfor %} -{%- endmacro %} - -{%- macro async(func) %} -{%- if func.is_async() %}async {% endif %} -{%- endmacro -%} - -{%- macro throws(func) %} -{%- if func.throws() %}throws {% endif %} -{%- endmacro -%} - -{%- macro try(func) %} -{%- if func.throws() %}try {% else %}try! {% endif %} -{%- endmacro -%} - -{%- macro docstring_value(maybe_docstring, indent_spaces) %} -{%- match maybe_docstring %} -{%- when Some(docstring) %} -{{ docstring|docstring(indent_spaces) }} -{%- else %} -{%- endmatch %} -{%- endmacro %} - -{%- macro docstring(defn, indent_spaces) %} -{%- call docstring_value(defn.docstring(), indent_spaces) %} -{%- endmacro %} +{# +// Template to call into rust. Used in several places. +// Variable names in `arg_list_decl` should match up with arg lists +// passed to rust via `arg_list_lowered` +#} + +{%- macro to_ffi_call(func) -%} + {%- call try(func) -%} + {%- match func.throws_type() -%} + {%- when Some with (e) -%} + rustCallWithError({{ e|ffi_converter_name }}.lift) { + {%- else -%} + rustCall() { + {%- endmatch %} + {{ func.ffi_func().name() }}({% call arg_list_lowered(func) -%} $0) +} +{%- endmacro -%} + +{%- macro to_ffi_call_with_prefix(prefix, func) -%} +{% call try(func) %} + {%- match func.throws_type() %} + {%- when Some with (e) %} + rustCallWithError({{ e|ffi_converter_name }}.lift) { + {%- else %} + rustCall() { + {% endmatch %} + {{ func.ffi_func().name() }}( + {{- prefix }}, {% call arg_list_lowered(func) -%} $0 + ) +} +{%- endmacro %} + +{%- macro arg_list_lowered(func) %} + {%- for arg in func.arguments() %} + {{ arg|lower_fn }}({{ arg.name()|var_name }}), + {%- endfor %} +{%- endmacro -%} + +{#- +// Arglist as used in Swift declarations of methods, functions and constructors. +// Note the var_name and type_name filters. +-#} + +{% macro arg_list_decl(func) %} + {%- for arg in func.arguments() -%} + {% if config.omit_argument_labels() %}_ {% endif %}{{ arg.name()|var_name }}: {{ arg|type_name -}} + {%- match arg.default_value() %} + {%- when Some with(literal) %} = {{ literal|literal_swift(arg) }} + {%- else %} + {%- endmatch %} + {%- if !loop.last %}, {% endif -%} + {%- endfor %} +{%- endmacro %} + +{#- +// Field lists as used in Swift declarations of Records and Enums. +// Note the var_name and type_name filters. +-#} +{% macro field_list_decl(item) %} + {%- for field in item.fields() -%} + {{ field.name()|var_name }}: {{ field|type_name -}} + {%- match field.default_value() %} + {%- when Some with(literal) %} = {{ literal|literal_swift(field) }} + {%- else %} + {%- endmatch -%} + {% if !loop.last %}, {% endif %} + {%- endfor %} +{%- endmacro %} + + +{% macro arg_list_protocol(func) %} + {%- for arg in func.arguments() -%} + {% if config.omit_argument_labels() %}_ {% endif %}{{ arg.name()|var_name }}: {{ arg|type_name -}} + {%- if !loop.last %}, {% endif -%} + {%- endfor %} +{%- endmacro %} + + +{%- macro async(func) %} +{%- if func.is_async() %}async{% endif %} +{%- endmacro -%} + +{%- macro throws(func) %} +{%- if func.throws() %}throws{% endif %} +{%- endmacro -%} + +{%- macro try(func) %} +{%- if func.throws() %}try {% else %}try! {% endif %} +{%- endmacro -%} diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/wrapper.swift b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/wrapper.swift index 17fdde74e07a..c34d348efb47 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/wrapper.swift +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/templates/wrapper.swift @@ -1,10 +1,5 @@ // This file was autogenerated by some hot garbage in the `uniffi` crate. // Trust me, you don't want to mess with it! - -// swiftlint:disable all - -{%- call swift::docstring_value(ci.namespace_docstring(), 0) %} - {%- import "macros.swift" as swift %} import Foundation {%- for imported_class in self.imports() %} @@ -20,7 +15,6 @@ import {{ config.ffi_module_name() }} {% include "RustBufferTemplate.swift" %} {% include "Helpers.swift" %} -{% include "HandleMap.swift" %} // Public interface members begin here. {{ type_helper_code }} @@ -72,5 +66,3 @@ private func uniffiEnsureInitialized() { fatalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } } - -// swiftlint:enable all diff --git a/third_party/rust/uniffi_bindgen/src/bindings/swift/test.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/test.rs index 195a77696b9b..c3b2f152771d 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/test.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/test.rs @@ -2,7 +2,10 @@ License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use crate::{bindings::RunScriptOptions, library_mode::generate_bindings, BindingGeneratorDefault}; +use crate::{ + bindings::{RunScriptOptions, TargetLanguage}, + library_mode::generate_bindings, +}; use anyhow::{bail, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; @@ -12,8 +15,6 @@ use std::io::Write; use std::process::{Command, Stdio}; use uniffi_testing::UniFFITestHelper; -use crate::bindings::TargetLanguage; - /// Run Swift tests for a UniFFI test fixture pub fn run_test(tmp_dir: &str, fixture_name: &str, script_file: &str) -> Result<()> { run_script( @@ -35,7 +36,7 @@ pub fn run_script( args: Vec, options: &RunScriptOptions, ) -> Result<()> { - let script_path = Utf8Path::new(script_file).canonicalize_utf8()?; + let script_path = Utf8Path::new(".").join(script_file).canonicalize_utf8()?; let test_helper = UniFFITestHelper::new(crate_name)?; let out_dir = test_helper.create_out_dir(tmp_dir, &script_path)?; let cdylib_path = test_helper.copy_cdylib_to_out_dir(&out_dir)?; @@ -125,17 +126,8 @@ struct GeneratedSources { impl GeneratedSources { fn new(crate_name: &str, cdylib_path: &Utf8Path, out_dir: &Utf8Path) -> Result { - let sources = generate_bindings( - cdylib_path, - None, - &BindingGeneratorDefault { - target_languages: vec![TargetLanguage::Swift], - try_format_code: false, - }, - None, - out_dir, - false, - )?; + let sources = + generate_bindings(cdylib_path, None, &[TargetLanguage::Swift], out_dir, false)?; let main_source = sources .iter() .find(|s| s.package.name == crate_name) @@ -177,7 +169,7 @@ fn create_command(program: &str, options: &RunScriptOptions) -> Command { if !options.show_compiler_messages { // This prevents most compiler messages, but not remarks command.arg("-suppress-warnings"); - // This gets the remarks. Note: swift will eventually get a `-suppress-remarks` argument, + // This gets the remarks. Note: swift will eventually get a `-supress-remarks` argument, // maybe we can eventually move to that command.stderr(Stdio::null()); } diff --git a/third_party/rust/uniffi_bindgen/src/interface/callbacks.rs b/third_party/rust/uniffi_bindgen/src/interface/callbacks.rs dissimilarity index 61% index f176a7a684d1..e3bca4f9664a 100644 --- a/third_party/rust/uniffi_bindgen/src/interface/callbacks.rs +++ b/third_party/rust/uniffi_bindgen/src/interface/callbacks.rs @@ -1,322 +1,149 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//! # Callback Interface definitions for a `ComponentInterface`. -//! -//! This module converts callback interface definitions from UDL into structures that -//! can be added to a `ComponentInterface`. A declaration in the UDL like this: -//! -//! ``` -//! # let ci = uniffi_bindgen::interface::ComponentInterface::from_webidl(r##" -//! # namespace example {}; -//! callback interface Example { -//! string hello(); -//! }; -//! # "##, "crate_name")?; -//! # Ok::<(), anyhow::Error>(()) -//! ``` -//! -//! Will result in a [`CallbackInterface`] member being added to the resulting -//! [`crate::ComponentInterface`]: -//! -//! ``` -//! # let ci = uniffi_bindgen::interface::ComponentInterface::from_webidl(r##" -//! # namespace example {}; -//! # callback interface Example { -//! # string hello(); -//! # }; -//! # "##, "crate_name")?; -//! let callback = ci.get_callback_interface_definition("Example").unwrap(); -//! assert_eq!(callback.name(), "Example"); -//! assert_eq!(callback.methods()[0].name(), "hello"); -//! # Ok::<(), anyhow::Error>(()) -//! ``` - -use std::iter; - -use heck::ToUpperCamelCase; -use uniffi_meta::Checksum; - -use super::ffi::{FfiArgument, FfiCallbackFunction, FfiField, FfiFunction, FfiStruct, FfiType}; -use super::object::Method; -use super::{AsType, Type, TypeIterator}; - -#[derive(Debug, Clone, Checksum)] -pub struct CallbackInterface { - pub(super) name: String, - pub(super) module_path: String, - pub(super) methods: Vec, - // We don't include the FFIFunc in the hash calculation, because: - // - it is entirely determined by the other fields, - // so excluding it is safe. - // - its `name` property includes a checksum derived from the very - // hash value we're trying to calculate here, so excluding it - // avoids a weird circular dependency in the calculation. - #[checksum_ignore] - pub(super) ffi_init_callback: FfiFunction, - #[checksum_ignore] - pub(super) docstring: Option, -} - -impl CallbackInterface { - pub fn name(&self) -> &str { - &self.name - } - - pub fn methods(&self) -> Vec<&Method> { - self.methods.iter().collect() - } - - pub fn ffi_init_callback(&self) -> &FfiFunction { - &self.ffi_init_callback - } - - pub(super) fn derive_ffi_funcs(&mut self) { - self.ffi_init_callback = - FfiFunction::callback_init(&self.module_path, &self.name, vtable_name(&self.name)); - } - - /// FfiCallbacks to define for our methods. - pub fn ffi_callbacks(&self) -> Vec { - ffi_callbacks(&self.name, &self.methods) - } - - /// The VTable FFI type - pub fn vtable(&self) -> FfiType { - FfiType::Struct(vtable_name(&self.name)) - } - - /// the VTable struct to define. - pub fn vtable_definition(&self) -> FfiStruct { - vtable_struct(&self.name, &self.methods) - } - - /// Vec of (ffi_callback, method) pairs - pub fn vtable_methods(&self) -> Vec<(FfiCallbackFunction, &Method)> { - self.methods - .iter() - .enumerate() - .map(|(i, method)| (method_ffi_callback(&self.name, method, i), method)) - .collect() - } - - pub fn iter_types(&self) -> TypeIterator<'_> { - Box::new(self.methods.iter().flat_map(Method::iter_types)) - } - - pub fn docstring(&self) -> Option<&str> { - self.docstring.as_deref() - } - - pub fn has_async_method(&self) -> bool { - self.methods.iter().any(Method::is_async) - } -} - -impl AsType for CallbackInterface { - fn as_type(&self) -> Type { - Type::CallbackInterface { - name: self.name.clone(), - module_path: self.module_path.clone(), - } - } -} - -impl TryFrom for CallbackInterface { - type Error = anyhow::Error; - - fn try_from(meta: uniffi_meta::CallbackInterfaceMetadata) -> anyhow::Result { - Ok(Self { - name: meta.name, - module_path: meta.module_path, - methods: Default::default(), - ffi_init_callback: Default::default(), - docstring: meta.docstring.clone(), - }) - } -} - -/// [FfiCallbackFunction] functions for the methods of a callback/trait interface -pub fn ffi_callbacks(trait_name: &str, methods: &[Method]) -> Vec { - methods - .iter() - .enumerate() - .map(|(i, method)| method_ffi_callback(trait_name, method, i)) - .collect() -} - -pub fn method_ffi_callback(trait_name: &str, method: &Method, index: usize) -> FfiCallbackFunction { - if !method.is_async() { - FfiCallbackFunction { - name: method_ffi_callback_name(trait_name, index), - arguments: iter::once(FfiArgument::new("uniffi_handle", FfiType::UInt64)) - .chain(method.arguments().into_iter().map(Into::into)) - .chain(iter::once(match method.return_type() { - Some(t) => FfiArgument::new("uniffi_out_return", FfiType::from(t).reference()), - None => FfiArgument::new("uniffi_out_return", FfiType::VoidPointer), - })) - .collect(), - has_rust_call_status_arg: true, - return_type: None, - } - } else { - let completion_callback = - ffi_foreign_future_complete(method.return_type().map(FfiType::from)); - FfiCallbackFunction { - name: method_ffi_callback_name(trait_name, index), - arguments: iter::once(FfiArgument::new("uniffi_handle", FfiType::UInt64)) - .chain(method.arguments().into_iter().map(Into::into)) - .chain([ - FfiArgument::new( - "uniffi_future_callback", - FfiType::Callback(completion_callback.name), - ), - FfiArgument::new("uniffi_callback_data", FfiType::UInt64), - FfiArgument::new( - "uniffi_out_return", - FfiType::Struct("ForeignFuture".to_owned()).reference(), - ), - ]) - .collect(), - has_rust_call_status_arg: false, - return_type: None, - } - } -} - -/// Result struct to pass to the completion callback for async methods -pub fn foreign_future_ffi_result_struct(return_ffi_type: Option) -> FfiStruct { - let return_type_name = - FfiType::return_type_name(return_ffi_type.as_ref()).to_upper_camel_case(); - FfiStruct { - name: format!("ForeignFutureStruct{return_type_name}"), - fields: match return_ffi_type { - Some(return_ffi_type) => vec![ - FfiField::new("return_value", return_ffi_type), - FfiField::new("call_status", FfiType::RustCallStatus), - ], - None => vec![ - // In Rust, `return_value` is `()` -- a ZST. - // ZSTs are not valid in `C`, but they also take up 0 space. - // Skip the `return_value` field to make the layout correct. - FfiField::new("call_status", FfiType::RustCallStatus), - ], - }, - } -} - -/// Definition for callback functions to complete an async callback interface method -pub fn ffi_foreign_future_complete(return_ffi_type: Option) -> FfiCallbackFunction { - let return_type_name = - FfiType::return_type_name(return_ffi_type.as_ref()).to_upper_camel_case(); - FfiCallbackFunction { - name: format!("ForeignFutureComplete{return_type_name}"), - arguments: vec![ - FfiArgument::new("callback_data", FfiType::UInt64), - FfiArgument::new( - "result", - FfiType::Struct(format!("ForeignFutureStruct{return_type_name}")), - ), - ], - return_type: None, - has_rust_call_status_arg: false, - } -} - -/// [FfiStruct] for a callback/trait interface VTable -/// -/// This struct has a FfiCallbackFunction field for each method, plus extra fields for special -/// methods -pub fn vtable_struct(trait_name: &str, methods: &[Method]) -> FfiStruct { - FfiStruct { - name: vtable_name(trait_name), - fields: methods - .iter() - .enumerate() - .map(|(i, method)| { - FfiField::new( - method.name(), - FfiType::Callback(format!("CallbackInterface{trait_name}Method{i}")), - ) - }) - .chain([FfiField::new( - "uniffi_free", - FfiType::Callback("CallbackInterfaceFree".to_owned()), - )]) - .collect(), - } -} - -pub fn method_ffi_callback_name(trait_name: &str, index: usize) -> String { - format!("CallbackInterface{trait_name}Method{index}") -} - -pub fn vtable_name(trait_name: &str) -> String { - format!("VTableCallbackInterface{trait_name}") -} - -#[cfg(test)] -mod test { - use super::super::ComponentInterface; - - #[test] - fn test_empty_interface() { - const UDL: &str = r#" - namespace test{}; - // Weird, but allowed. - callback interface Testing {}; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!(ci.callback_interface_definitions().len(), 1); - assert_eq!( - ci.get_callback_interface_definition("Testing") - .unwrap() - .methods() - .len(), - 0 - ); - } - - #[test] - fn test_multiple_interfaces() { - const UDL: &str = r#" - namespace test{}; - callback interface One { - void one(); - }; - callback interface Two { - u32 two(); - u64 too(); - }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!(ci.callback_interface_definitions().len(), 2); - - let callbacks_one = ci.get_callback_interface_definition("One").unwrap(); - assert_eq!(callbacks_one.methods().len(), 1); - assert_eq!(callbacks_one.methods()[0].name(), "one"); - - let callbacks_two = ci.get_callback_interface_definition("Two").unwrap(); - assert_eq!(callbacks_two.methods().len(), 2); - assert_eq!(callbacks_two.methods()[0].name(), "two"); - assert_eq!(callbacks_two.methods()[1].name(), "too"); - } - - #[test] - fn test_docstring_callback_interface() { - const UDL: &str = r#" - namespace test{}; - /// informative docstring - callback interface Testing { }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_callback_interface_definition("Testing") - .unwrap() - .docstring() - .unwrap(), - "informative docstring" - ); - } -} +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! # Callback Interface definitions for a `ComponentInterface`. +//! +//! This module converts callback interface definitions from UDL into structures that +//! can be added to a `ComponentInterface`. A declaration in the UDL like this: +//! +//! ``` +//! # let ci = uniffi_bindgen::interface::ComponentInterface::from_webidl(r##" +//! # namespace example {}; +//! callback interface Example { +//! string hello(); +//! }; +//! # "##, "crate_name")?; +//! # Ok::<(), anyhow::Error>(()) +//! ``` +//! +//! Will result in a [`CallbackInterface`] member being added to the resulting +//! [`crate::ComponentInterface`]: +//! +//! ``` +//! # let ci = uniffi_bindgen::interface::ComponentInterface::from_webidl(r##" +//! # namespace example {}; +//! # callback interface Example { +//! # string hello(); +//! # }; +//! # "##, "crate_name")?; +//! let callback = ci.get_callback_interface_definition("Example").unwrap(); +//! assert_eq!(callback.name(), "Example"); +//! assert_eq!(callback.methods()[0].name(), "hello"); +//! # Ok::<(), anyhow::Error>(()) +//! ``` + +use uniffi_meta::Checksum; + +use super::ffi::{FfiArgument, FfiFunction, FfiType}; +use super::object::Method; +use super::{AsType, Type, TypeIterator}; + +#[derive(Debug, Clone, Checksum)] +pub struct CallbackInterface { + pub(super) name: String, + pub(super) module_path: String, + pub(super) methods: Vec, + // We don't include the FFIFunc in the hash calculation, because: + // - it is entirely determined by the other fields, + // so excluding it is safe. + // - its `name` property includes a checksum derived from the very + // hash value we're trying to calculate here, so excluding it + // avoids a weird circular dependency in the calculation. + #[checksum_ignore] + pub(super) ffi_init_callback: FfiFunction, +} + +impl CallbackInterface { + pub fn new(name: String, module_path: String) -> CallbackInterface { + CallbackInterface { + name, + module_path, + methods: Default::default(), + ffi_init_callback: Default::default(), + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn methods(&self) -> Vec<&Method> { + self.methods.iter().collect() + } + + pub fn ffi_init_callback(&self) -> &FfiFunction { + &self.ffi_init_callback + } + + pub(super) fn derive_ffi_funcs(&mut self) { + self.ffi_init_callback.name = + uniffi_meta::init_callback_fn_symbol_name(&self.module_path, &self.name); + self.ffi_init_callback.arguments = vec![FfiArgument { + name: "callback_stub".to_string(), + type_: FfiType::ForeignCallback, + }]; + self.ffi_init_callback.return_type = None; + } + + pub fn iter_types(&self) -> TypeIterator<'_> { + Box::new(self.methods.iter().flat_map(Method::iter_types)) + } +} + +impl AsType for CallbackInterface { + fn as_type(&self) -> Type { + Type::CallbackInterface { + name: self.name.clone(), + module_path: self.module_path.clone(), + } + } +} + +#[cfg(test)] +mod test { + use super::super::ComponentInterface; + + #[test] + fn test_empty_interface() { + const UDL: &str = r#" + namespace test{}; + // Weird, but allowed. + callback interface Testing {}; + "#; + let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); + assert_eq!(ci.callback_interface_definitions().len(), 1); + assert_eq!( + ci.get_callback_interface_definition("Testing") + .unwrap() + .methods() + .len(), + 0 + ); + } + + #[test] + fn test_multiple_interfaces() { + const UDL: &str = r#" + namespace test{}; + callback interface One { + void one(); + }; + callback interface Two { + u32 two(); + u64 too(); + }; + "#; + let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); + assert_eq!(ci.callback_interface_definitions().len(), 2); + + let callbacks_one = ci.get_callback_interface_definition("One").unwrap(); + assert_eq!(callbacks_one.methods().len(), 1); + assert_eq!(callbacks_one.methods()[0].name(), "one"); + + let callbacks_two = ci.get_callback_interface_definition("Two").unwrap(); + assert_eq!(callbacks_two.methods().len(), 2); + assert_eq!(callbacks_two.methods()[0].name(), "two"); + assert_eq!(callbacks_two.methods()[1].name(), "too"); + } +} diff --git a/third_party/rust/uniffi_bindgen/src/interface/enum_.rs b/third_party/rust/uniffi_bindgen/src/interface/enum_.rs index a666cc3605fc..82baf1dd50f8 100644 --- a/third_party/rust/uniffi_bindgen/src/interface/enum_.rs +++ b/third_party/rust/uniffi_bindgen/src/interface/enum_.rs @@ -94,9 +94,7 @@ //! //! ``` //! # let ci = uniffi_bindgen::interface::ComponentInterface::from_webidl(r##" -//! # namespace example { -//! # [Throws=Example] void func(); -//! # }; +//! # namespace example {}; //! # [Error] //! # enum Example { //! # "one", @@ -132,9 +130,7 @@ //! //! ``` //! # let ci = uniffi_bindgen::interface::ComponentInterface::from_webidl(r##" -//! # namespace example { -//! # [Throws=Example] void func(); -//! # }; +//! # namespace example {}; //! # [Error] //! # interface Example { //! # one(); @@ -163,7 +159,7 @@ use anyhow::Result; use uniffi_meta::Checksum; use super::record::Field; -use super::{AsType, Literal, Type, TypeIterator}; +use super::{AsType, Type, TypeIterator}; /// Represents an enum with named variants, each of which may have named /// and typed fields. @@ -174,7 +170,6 @@ use super::{AsType, Literal, Type, TypeIterator}; pub struct Enum { pub(super) name: String, pub(super) module_path: String, - pub(super) discr_type: Option, pub(super) variants: Vec, // NOTE: `flat` is a misleading name and to make matters worse, has 2 different // meanings depending on the context :( @@ -194,9 +189,6 @@ pub struct Enum { // * For an Enum not used as an error but which has no variants with data, `flat` will be // false when generating the scaffolding but `true` when generating bindings. pub(super) flat: bool, - pub(super) non_exhaustive: bool, - #[checksum_ignore] - pub(super) docstring: Option, } impl Enum { @@ -208,61 +200,14 @@ impl Enum { &self.variants } - // Get the literal value to use for the specified variant's discriminant. - // Follows Rust's rules when mixing specified and unspecified values; please - // file a bug if you find a case where it does not. - // However, it *does not* attempt to handle error cases - either cases where - // a discriminant is not unique, or where a discriminant would overflow the - // repr. The intention is that the Rust compiler itself will fail to build - // in those cases, so by the time this get's run we can be confident these - // error cases can't exist. - pub fn variant_discr(&self, variant_index: usize) -> Result { - if variant_index >= self.variants.len() { - anyhow::bail!("Invalid variant index {variant_index}"); - } - let mut next = 0; - let mut this; - let mut this_lit = Literal::new_uint(0); - for v in self.variants().iter().take(variant_index + 1) { - (this, this_lit) = match v.discr { - None => ( - next, - if (next as i64) < 0 { - Literal::new_int(next as i64) - } else { - Literal::new_uint(next) - }, - ), - Some(Literal::UInt(v, _, _)) => (v, Literal::new_uint(v)), - // in-practice, Literal::Int == a negative number. - Some(Literal::Int(v, _, _)) => (v as u64, Literal::new_int(v)), - _ => anyhow::bail!("Invalid literal type {v:?}"), - }; - next = this.wrapping_add(1); - } - Ok(this_lit) - } - - pub fn variant_discr_type(&self) -> &Option { - &self.discr_type - } - pub fn is_flat(&self) -> bool { self.flat } - pub fn is_non_exhaustive(&self) -> bool { - self.non_exhaustive - } - pub fn iter_types(&self) -> TypeIterator<'_> { Box::new(self.variants.iter().flat_map(Variant::iter_types)) } - pub fn docstring(&self) -> Option<&str> { - self.docstring.as_deref() - } - // Sadly can't use TryFrom due to the 'is_flat' complication. pub fn try_from_meta(meta: uniffi_meta::EnumMetadata, flat: bool) -> Result { // This is messy - error enums are considered "flat" if the user @@ -273,15 +218,12 @@ impl Enum { Ok(Self { name: meta.name, module_path: meta.module_path, - discr_type: meta.discr_type, variants: meta .variants .into_iter() .map(TryInto::try_into) .collect::>()?, flat, - non_exhaustive: meta.non_exhaustive, - docstring: meta.docstring.clone(), }) } } @@ -301,10 +243,7 @@ impl AsType for Enum { #[derive(Debug, Clone, Default, PartialEq, Eq, Checksum)] pub struct Variant { pub(super) name: String, - pub(super) discr: Option, pub(super) fields: Vec, - #[checksum_ignore] - pub(super) docstring: Option, } impl Variant { @@ -320,14 +259,6 @@ impl Variant { !self.fields.is_empty() } - pub fn has_nameless_fields(&self) -> bool { - self.fields.iter().any(|f| f.name.is_empty()) - } - - pub fn docstring(&self) -> Option<&str> { - self.docstring.as_deref() - } - pub fn iter_types(&self) -> TypeIterator<'_> { Box::new(self.fields.iter().flat_map(Field::iter_types)) } @@ -339,13 +270,11 @@ impl TryFrom for Variant { fn try_from(meta: uniffi_meta::VariantMetadata) -> Result { Ok(Self { name: meta.name, - discr: meta.discr, fields: meta .fields .into_iter() .map(TryInto::try_into) .collect::>()?, - docstring: meta.docstring.clone(), }) } } @@ -518,10 +447,7 @@ mod test { #[test] fn test_variants() { const UDL: &str = r#" - namespace test{ - [Throws=Testing] - void func(); - }; + namespace test{}; [Error] enum Testing { "one", "two", "three" }; "#; @@ -560,10 +486,7 @@ mod test { #[test] fn test_variant_data() { const UDL: &str = r#" - namespace test{ - [Throws=Testing] - void func(); - }; + namespace test{}; [Error] interface Testing { @@ -641,141 +564,4 @@ mod test { vec!["Normal", "Error"] ); } - - fn variant(val: Option) -> Variant { - Variant { - name: "v".to_string(), - discr: val.map(Literal::new_uint), - fields: vec![], - docstring: None, - } - } - - fn check_discrs(e: &mut Enum, vs: Vec) -> Vec { - e.variants = vs; - (0..e.variants.len()) - .map(|i| e.variant_discr(i).unwrap()) - .map(|l| match l { - Literal::UInt(v, _, _) => v, - _ => unreachable!(), - }) - .collect() - } - - #[test] - fn test_variant_values() { - let mut e = Enum { - module_path: "test".to_string(), - name: "test".to_string(), - discr_type: None, - variants: vec![], - flat: false, - non_exhaustive: false, - docstring: None, - }; - - assert!(e.variant_discr(0).is_err()); - - // single values - assert_eq!(check_discrs(&mut e, vec![variant(None)]), vec![0]); - assert_eq!(check_discrs(&mut e, vec![variant(Some(3))]), vec![3]); - - // no values - assert_eq!( - check_discrs(&mut e, vec![variant(None), variant(None)]), - vec![0, 1] - ); - - // values - assert_eq!( - check_discrs(&mut e, vec![variant(Some(1)), variant(Some(3))]), - vec![1, 3] - ); - - // mixed values - assert_eq!( - check_discrs(&mut e, vec![variant(None), variant(Some(3)), variant(None)]), - vec![0, 3, 4] - ); - - assert_eq!( - check_discrs( - &mut e, - vec![variant(Some(4)), variant(None), variant(Some(1))] - ), - vec![4, 5, 1] - ); - } - - #[test] - fn test_docstring_enum() { - const UDL: &str = r#" - namespace test{}; - /// informative docstring - enum Testing { "foo" }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_enum_definition("Testing") - .unwrap() - .docstring() - .unwrap(), - "informative docstring" - ); - } - - #[test] - fn test_docstring_enum_variant() { - const UDL: &str = r#" - namespace test{}; - enum Testing { - /// informative docstring - "foo" - }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_enum_definition("Testing").unwrap().variants()[0] - .docstring() - .unwrap(), - "informative docstring" - ); - } - - #[test] - fn test_docstring_associated_enum() { - const UDL: &str = r#" - namespace test{}; - /// informative docstring - [Enum] - interface Testing { }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_enum_definition("Testing") - .unwrap() - .docstring() - .unwrap(), - "informative docstring" - ); - } - - #[test] - fn test_docstring_associated_enum_variant() { - const UDL: &str = r#" - namespace test{}; - [Enum] - interface Testing { - /// informative docstring - testing(); - }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_enum_definition("Testing").unwrap().variants()[0] - .docstring() - .unwrap(), - "informative docstring" - ); - } } diff --git a/third_party/rust/uniffi_bindgen/src/interface/ffi.rs b/third_party/rust/uniffi_bindgen/src/interface/ffi.rs index b27cb7847718..d18aaf8262a7 100644 --- a/third_party/rust/uniffi_bindgen/src/interface/ffi.rs +++ b/third_party/rust/uniffi_bindgen/src/interface/ffi.rs @@ -47,49 +47,20 @@ pub enum FfiType { /// A borrowed reference to some raw bytes owned by foreign language code. /// The provider of this reference must keep it alive for the duration of the receiving call. ForeignBytes, - /// Pointer to a callback function. The inner value which matches one of the callback - /// definitions in [crate::ComponentInterface::ffi_definitions]. - Callback(String), - /// Pointer to a FFI struct (e.g. a VTable). The inner value matches one of the struct - /// definitions in [crate::ComponentInterface::ffi_definitions]. - Struct(String), - /// Opaque 64-bit handle - /// - /// These are used to pass objects across the FFI. - Handle, - RustCallStatus, - /// Pointer to an FfiType. - Reference(Box), - /// Opaque pointer - VoidPointer, -} - -impl FfiType { - pub fn reference(self) -> FfiType { - FfiType::Reference(Box::new(self)) - } - - /// Unique name for an FFI return type - pub fn return_type_name(return_type: Option<&FfiType>) -> String { - match return_type { - Some(t) => match t { - FfiType::UInt8 => "u8".to_owned(), - FfiType::Int8 => "i8".to_owned(), - FfiType::UInt16 => "u16".to_owned(), - FfiType::Int16 => "i16".to_owned(), - FfiType::UInt32 => "u32".to_owned(), - FfiType::Int32 => "i32".to_owned(), - FfiType::UInt64 => "u64".to_owned(), - FfiType::Int64 => "i64".to_owned(), - FfiType::Float32 => "f32".to_owned(), - FfiType::Float64 => "f64".to_owned(), - FfiType::RustArcPtr(_) => "pointer".to_owned(), - FfiType::RustBuffer(_) => "rust_buffer".to_owned(), - _ => unimplemented!("FFI return type: {t:?}"), - }, - None => "void".to_owned(), - } - } + /// Pointer to a callback function that handles all callbacks on the foreign language side. + ForeignCallback, + /// Pointer-sized opaque handle that represents a foreign executor. Foreign bindings can + /// either use an actual pointer or a usized integer. + ForeignExecutorHandle, + /// Pointer to the callback function that's invoked to schedule calls with a ForeignExecutor + ForeignExecutorCallback, + /// Pointer to a Rust future + RustFutureHandle, + /// Continuation function for a Rust future + RustFutureContinuationCallback, + RustFutureContinuationData, + // TODO: you can imagine a richer structural typesystem here, e.g. `Ref` or something. + // We don't need that yet and it's possible we never will, so it isn't here for now. } /// When passing data across the FFI, each `Type` value will be lowered into a corresponding @@ -123,6 +94,7 @@ impl From<&Type> for FfiType { Type::Object { name, .. } => FfiType::RustArcPtr(name.to_owned()), // Callback interfaces are passed as opaque integer handles. Type::CallbackInterface { .. } => FfiType::UInt64, + Type::ForeignExecutor => FfiType::ForeignExecutorHandle, // Other types are serialized into a bytebuffer and deserialized on the other side. Type::Enum { .. } | Type::Record { .. } @@ -135,11 +107,6 @@ impl From<&Type> for FfiType { name, kind: ExternalKind::Interface, .. - } - | Type::External { - name, - kind: ExternalKind::Trait, - .. } => FfiType::RustArcPtr(name.clone()), Type::External { name, @@ -164,24 +131,6 @@ impl From<&&Type> for FfiType { } } -/// An Ffi definition -#[derive(Debug, Clone)] -pub enum FfiDefinition { - Function(FfiFunction), - CallbackFunction(FfiCallbackFunction), - Struct(FfiStruct), -} - -impl FfiDefinition { - pub fn name(&self) -> &str { - match self { - Self::Function(f) => f.name(), - Self::CallbackFunction(f) => f.name(), - Self::Struct(s) => s.name(), - } - } -} - /// Represents an "extern C"-style function that will be part of the FFI. /// /// These can't be declared explicitly in the UDL, but rather, are derived automatically @@ -201,19 +150,6 @@ pub struct FfiFunction { } impl FfiFunction { - pub fn callback_init(module_path: &str, trait_name: &str, vtable_name: String) -> Self { - Self { - name: uniffi_meta::init_callback_vtable_fn_symbol_name(module_path, trait_name), - arguments: vec![FfiArgument { - name: "vtable".to_string(), - type_: FfiType::Struct(vtable_name).reference(), - }], - return_type: None, - has_rust_call_status_arg: false, - ..Self::default() - } - } - pub fn name(&self) -> &str { &self.name } @@ -245,7 +181,7 @@ impl FfiFunction { ) { self.arguments = args.into_iter().collect(); if self.is_async() { - self.return_type = Some(FfiType::Handle); + self.return_type = Some(FfiType::RustFutureHandle); self.has_rust_call_status_arg = false; } else { self.return_type = return_type; @@ -276,113 +212,14 @@ pub struct FfiArgument { } impl FfiArgument { - pub fn new(name: impl Into, type_: FfiType) -> Self { - Self { - name: name.into(), - type_, - } - } - pub fn name(&self) -> &str { &self.name } - pub fn type_(&self) -> FfiType { self.type_.clone() } } -/// Represents an "extern C"-style callback function -/// -/// These are defined in the foreign code and passed to Rust as a function pointer. -#[derive(Debug, Default, Clone)] -pub struct FfiCallbackFunction { - // Name for this function type. This matches the value inside `FfiType::Callback` - pub(super) name: String, - pub(super) arguments: Vec, - pub(super) return_type: Option, - pub(super) has_rust_call_status_arg: bool, -} - -impl FfiCallbackFunction { - pub fn name(&self) -> &str { - &self.name - } - - pub fn arguments(&self) -> Vec<&FfiArgument> { - self.arguments.iter().collect() - } - - pub fn return_type(&self) -> Option<&FfiType> { - self.return_type.as_ref() - } - - pub fn has_rust_call_status_arg(&self) -> bool { - self.has_rust_call_status_arg - } -} - -/// Represents a repr(C) struct used in the FFI -#[derive(Debug, Default, Clone)] -pub struct FfiStruct { - pub(super) name: String, - pub(super) fields: Vec, -} - -impl FfiStruct { - /// Get the name of this struct - pub fn name(&self) -> &str { - &self.name - } - - /// Get the fields for this struct - pub fn fields(&self) -> &[FfiField] { - &self.fields - } -} - -/// Represents a field of an [FfiStruct] -#[derive(Debug, Clone)] -pub struct FfiField { - pub(super) name: String, - pub(super) type_: FfiType, -} - -impl FfiField { - pub fn new(name: impl Into, type_: FfiType) -> Self { - Self { - name: name.into(), - type_, - } - } - - pub fn name(&self) -> &str { - &self.name - } - - pub fn type_(&self) -> FfiType { - self.type_.clone() - } -} - -impl From for FfiDefinition { - fn from(value: FfiFunction) -> FfiDefinition { - FfiDefinition::Function(value) - } -} - -impl From for FfiDefinition { - fn from(value: FfiStruct) -> FfiDefinition { - FfiDefinition::Struct(value) - } -} - -impl From for FfiDefinition { - fn from(value: FfiCallbackFunction) -> FfiDefinition { - FfiDefinition::CallbackFunction(value) - } -} - #[cfg(test)] mod test { // There's not really much to test here to be honest, diff --git a/third_party/rust/uniffi_bindgen/src/interface/function.rs b/third_party/rust/uniffi_bindgen/src/interface/function.rs index 8effc4c87665..2d18288c1c6f 100644 --- a/third_party/rust/uniffi_bindgen/src/interface/function.rs +++ b/third_party/rust/uniffi_bindgen/src/interface/function.rs @@ -59,8 +59,6 @@ pub struct Function { // avoids a weird circular dependency in the calculation. #[checksum_ignore] pub(super) ffi_func: FfiFunction, - #[checksum_ignore] - pub(super) docstring: Option, pub(super) throws: Option, pub(super) checksum_fn_name: String, // Force a checksum value, or we'll fallback to the trait. @@ -130,10 +128,6 @@ impl Function { .chain(self.return_type.iter().flat_map(Type::iter_types)), ) } - - pub fn docstring(&self) -> Option<&str> { - self.docstring.as_deref() - } } impl From for Argument { @@ -169,7 +163,6 @@ impl From for Function { arguments, return_type, ffi_func, - docstring: meta.docstring.clone(), throws: meta.throws, checksum_fn_name, checksum: meta.checksum, @@ -249,9 +242,6 @@ pub trait Callable { fn return_type(&self) -> Option; fn throws_type(&self) -> Option; fn is_async(&self) -> bool; - fn takes_self(&self) -> bool { - false - } fn result_type(&self) -> ResultType { ResultType { return_type: self.return_type(), @@ -321,10 +311,6 @@ impl Callable for &T { fn is_async(&self) -> bool { (*self).is_async() } - - fn takes_self(&self) -> bool { - (*self).takes_self() - } } #[cfg(test)] @@ -378,22 +364,4 @@ mod test { ); Ok(()) } - - #[test] - fn test_docstring_function() { - const UDL: &str = r#" - namespace test { - /// informative docstring - void testing(); - }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_function_definition("testing") - .unwrap() - .docstring() - .unwrap(), - "informative docstring" - ); - } } diff --git a/third_party/rust/uniffi_bindgen/src/interface/mod.rs b/third_party/rust/uniffi_bindgen/src/interface/mod.rs index 90a941637a58..8e4df2149b4f 100644 --- a/third_party/rust/uniffi_bindgen/src/interface/mod.rs +++ b/third_party/rust/uniffi_bindgen/src/interface/mod.rs @@ -67,9 +67,7 @@ mod record; pub use record::{Field, Record}; pub mod ffi; -pub use ffi::{ - FfiArgument, FfiCallbackFunction, FfiDefinition, FfiField, FfiFunction, FfiStruct, FfiType, -}; +pub use ffi::{FfiArgument, FfiFunction, FfiType}; pub use uniffi_meta::Radix; use uniffi_meta::{ ConstructorMetadata, LiteralMetadata, NamespaceMetadata, ObjectMetadata, TraitMethodMetadata, @@ -141,11 +139,6 @@ impl ComponentInterface { self.types.namespace ); } - - if group.namespace_docstring.is_some() { - self.types.namespace_docstring = group.namespace_docstring.clone(); - } - // Unconditionally add the String type, which is used by the panic handling self.types.add_known_type(&uniffi_meta::Type::String)?; crate::macro_metadata::add_group_to_ci(self, group)?; @@ -160,10 +153,6 @@ impl ComponentInterface { &self.types.namespace.name } - pub fn namespace_docstring(&self) -> Option<&str> { - self.types.namespace_docstring.as_deref() - } - pub fn uniffi_contract_version(&self) -> u32 { // This is set by the scripts in the version-mismatch fixture let force_version = std::env::var("UNIFFI_FORCE_CONTRACT_VERSION"); @@ -215,29 +204,6 @@ impl ComponentInterface { self.objects.iter().find(|o| o.name == name) } - fn callback_interface_callback_definitions( - &self, - ) -> impl IntoIterator + '_ { - self.callback_interfaces - .iter() - .flat_map(|cbi| cbi.ffi_callbacks()) - .chain(self.objects.iter().flat_map(|o| o.ffi_callbacks())) - } - - /// Get the definitions for callback FFI functions - /// - /// These are defined by the foreign code and invoked by Rust. - fn callback_interface_vtable_definitions(&self) -> impl IntoIterator + '_ { - self.callback_interface_definitions() - .iter() - .map(|cbi| cbi.vtable_definition()) - .chain( - self.object_definitions() - .iter() - .flat_map(|o| o.vtable_definition()), - ) - } - /// Get the definitions for every Callback Interface type in the interface. pub fn callback_interface_definitions(&self) -> &[CallbackInterface] { &self.callback_interfaces @@ -249,17 +215,6 @@ impl ComponentInterface { self.callback_interfaces.iter().find(|o| o.name == name) } - /// Get the definitions for every Callback Interface type in the interface. - pub fn has_async_callback_interface_definition(&self) -> bool { - self.callback_interfaces - .iter() - .any(|cbi| cbi.has_async_method()) - || self - .objects - .iter() - .any(|o| o.has_callback_interface() && o.has_async_method()) - } - /// Get the definitions for every Method type in the interface. pub fn iter_callables(&self) -> impl Iterator { // Each of the `as &dyn Callable` casts is a trivial cast, but it seems like the clearest @@ -286,19 +241,13 @@ impl ComponentInterface { let fielded = !e.is_flat(); // For flat errors, we should only generate read() methods if we need them to support // callback interface errors - let used_in_foreign_interface = self + let used_in_callback_interface = self .callback_interface_definitions() .iter() .flat_map(|cb| cb.methods()) - .chain( - self.object_definitions() - .iter() - .filter(|o| o.has_callback_interface()) - .flat_map(|o| o.methods()), - ) .any(|m| m.throws_type() == Some(&e.as_type())); - self.is_name_used_as_error(&e.name) && (fielded || used_in_foreign_interface) + self.is_name_used_as_error(&e.name) && (fielded || used_in_callback_interface) } /// Get details about all `Type::External` types. @@ -355,17 +304,8 @@ impl ComponentInterface { /// This is important to know in language bindings that cannot integrate object types /// tightly with the host GC, and hence need to perform manual destruction of objects. pub fn item_contains_object_references(&self, item: &Type) -> bool { - // this is surely broken for external records with object refs? - self.iter_types_in_item(item).any(|t| { - matches!( - t, - Type::Object { .. } - | Type::External { - kind: ExternalKind::Interface, - .. - } - ) - }) + self.iter_types_in_item(item) + .any(|t| matches!(t, Type::Object { .. })) } /// Check whether the given item contains any (possibly nested) unsigned types @@ -395,13 +335,6 @@ impl ComponentInterface { .any(|t| matches!(t, Type::Map { .. })) } - /// Check whether the interface contains any object types - pub fn contains_object_types(&self) -> bool { - self.types - .iter_known_types() - .any(|t| matches!(t, Type::Object { .. })) - } - // The namespace to use in crate-level FFI function definitions. Not used as the ffi // namespace for types - each type has its own `module_path` which is used for them. fn ffi_namespace(&self) -> &str { @@ -431,7 +364,7 @@ impl ComponentInterface { is_async: false, arguments: vec![FfiArgument { name: "size".to_string(), - type_: FfiType::UInt64, + type_: FfiType::Int32, }], return_type: Some(FfiType::RustBuffer(None)), has_rust_call_status_arg: true, @@ -487,7 +420,7 @@ impl ComponentInterface { }, FfiArgument { name: "additional".to_string(), - type_: FfiType::UInt64, + type_: FfiType::Int32, }, ], return_type: Some(FfiType::RustBuffer(None)), @@ -496,6 +429,24 @@ impl ComponentInterface { } } + /// Builtin FFI function to set the Rust Future continuation callback + pub fn ffi_rust_future_continuation_callback_set(&self) -> FfiFunction { + FfiFunction { + name: format!( + "ffi_{}_rust_future_continuation_callback_set", + self.ffi_namespace() + ), + arguments: vec![FfiArgument { + name: "callback".to_owned(), + type_: FfiType::RustFutureContinuationCallback, + }], + return_type: None, + is_async: false, + has_rust_call_status_arg: false, + is_object_free_function: false, + } + } + /// Builtin FFI function to poll a Rust future. pub fn ffi_rust_future_poll(&self, return_ffi_type: Option) -> FfiFunction { FfiFunction { @@ -504,15 +455,12 @@ impl ComponentInterface { arguments: vec![ FfiArgument { name: "handle".to_owned(), - type_: FfiType::Handle, - }, - FfiArgument { - name: "callback".to_owned(), - type_: FfiType::Callback("RustFutureContinuationCallback".to_owned()), + type_: FfiType::RustFutureHandle, }, + // Data to pass to the continuation FfiArgument { - name: "callback_data".to_owned(), - type_: FfiType::Handle, + name: "uniffi_callback".to_owned(), + type_: FfiType::RustFutureContinuationData, }, ], return_type: None, @@ -530,7 +478,7 @@ impl ComponentInterface { is_async: false, arguments: vec![FfiArgument { name: "handle".to_owned(), - type_: FfiType::Handle, + type_: FfiType::RustFutureHandle, }], return_type: return_ffi_type, has_rust_call_status_arg: true, @@ -545,7 +493,7 @@ impl ComponentInterface { is_async: false, arguments: vec![FfiArgument { name: "handle".to_owned(), - type_: FfiType::Handle, + type_: FfiType::RustFutureHandle, }], return_type: None, has_rust_call_status_arg: false, @@ -560,7 +508,7 @@ impl ComponentInterface { is_async: false, arguments: vec![FfiArgument { name: "handle".to_owned(), - type_: FfiType::Handle, + type_: FfiType::RustFutureHandle, }], return_type: None, has_rust_call_status_arg: false, @@ -570,17 +518,29 @@ impl ComponentInterface { fn rust_future_ffi_fn_name(&self, base_name: &str, return_ffi_type: Option) -> String { let namespace = self.ffi_namespace(); - let return_type_name = FfiType::return_type_name(return_ffi_type.as_ref()); - format!("ffi_{namespace}_{base_name}_{return_type_name}") + match return_ffi_type { + Some(t) => match t { + FfiType::UInt8 => format!("ffi_{namespace}_{base_name}_u8"), + FfiType::Int8 => format!("ffi_{namespace}_{base_name}_i8"), + FfiType::UInt16 => format!("ffi_{namespace}_{base_name}_u16"), + FfiType::Int16 => format!("ffi_{namespace}_{base_name}_i16"), + FfiType::UInt32 => format!("ffi_{namespace}_{base_name}_u32"), + FfiType::Int32 => format!("ffi_{namespace}_{base_name}_i32"), + FfiType::UInt64 => format!("ffi_{namespace}_{base_name}_u64"), + FfiType::Int64 => format!("ffi_{namespace}_{base_name}_i64"), + FfiType::Float32 => format!("ffi_{namespace}_{base_name}_f32"), + FfiType::Float64 => format!("ffi_{namespace}_{base_name}_f64"), + FfiType::RustArcPtr(_) => format!("ffi_{namespace}_{base_name}_pointer"), + FfiType::RustBuffer(_) => format!("ffi_{namespace}_{base_name}_rust_buffer"), + _ => unimplemented!("FFI return type: {t:?}"), + }, + None => format!("ffi_{namespace}_{base_name}_void"), + } } /// Does this interface contain async functions? pub fn has_async_fns(&self) -> bool { self.iter_ffi_function_definitions().any(|f| f.is_async()) - || self - .callback_interfaces - .iter() - .any(CallbackInterface::has_async_method) } /// Iterate over `T` parameters of the `FutureCallback` callbacks in this interface @@ -601,73 +561,6 @@ impl ComponentInterface { unique_results.into_iter() } - /// Iterate over all Ffi definitions - pub fn ffi_definitions(&self) -> impl Iterator + '_ { - // Note: for languages like Python it's important to keep things in dependency order. - // For example some FFI function definitions depend on FFI struct definitions, so the - // function definitions come last. - self.builtin_ffi_definitions() - .into_iter() - .chain( - self.callback_interface_callback_definitions() - .into_iter() - .map(Into::into), - ) - .chain( - self.callback_interface_vtable_definitions() - .into_iter() - .map(Into::into), - ) - .chain(self.iter_ffi_function_definitions().map(Into::into)) - } - - fn builtin_ffi_definitions(&self) -> impl IntoIterator + '_ { - [ - FfiCallbackFunction { - name: "RustFutureContinuationCallback".to_owned(), - arguments: vec![ - FfiArgument::new("data", FfiType::UInt64), - FfiArgument::new("poll_result", FfiType::Int8), - ], - return_type: None, - has_rust_call_status_arg: false, - } - .into(), - FfiCallbackFunction { - name: "ForeignFutureFree".to_owned(), - arguments: vec![FfiArgument::new("handle", FfiType::UInt64)], - return_type: None, - has_rust_call_status_arg: false, - } - .into(), - FfiCallbackFunction { - name: "CallbackInterfaceFree".to_owned(), - arguments: vec![FfiArgument::new("handle", FfiType::UInt64)], - return_type: None, - has_rust_call_status_arg: false, - } - .into(), - FfiStruct { - name: "ForeignFuture".to_owned(), - fields: vec![ - FfiField::new("handle", FfiType::UInt64), - FfiField::new("free", FfiType::Callback("ForeignFutureFree".to_owned())), - ], - } - .into(), - ] - .into_iter() - .chain( - self.all_possible_return_ffi_types() - .flat_map(|return_type| { - [ - callbacks::foreign_future_ffi_result_struct(return_type.clone()).into(), - callbacks::ffi_foreign_future_complete(return_type).into(), - ] - }), - ) - } - /// List the definitions of all FFI functions in the interface. /// /// The set of FFI functions is derived automatically from the set of higher-level types @@ -676,8 +569,9 @@ impl ComponentInterface { self.iter_user_ffi_function_definitions() .cloned() .chain(self.iter_rust_buffer_ffi_function_definitions()) - .chain(self.iter_futures_ffi_function_definitions()) + .chain(self.iter_futures_ffi_function_definitons()) .chain(self.iter_checksum_ffi_functions()) + .chain(self.ffi_foreign_executor_callback_set()) .chain([self.ffi_uniffi_contract_version()]) } @@ -724,8 +618,9 @@ impl ComponentInterface { .into_iter() } - fn all_possible_return_ffi_types(&self) -> impl Iterator> { - [ + /// List all FFI functions definitions for async functionality. + pub fn iter_futures_ffi_function_definitons(&self) -> impl Iterator + '_ { + let all_possible_return_ffi_types = [ Some(FfiType::UInt8), Some(FfiType::Int8), Some(FfiType::UInt16), @@ -736,26 +631,46 @@ impl ComponentInterface { Some(FfiType::Int64), Some(FfiType::Float32), Some(FfiType::Float64), - // RustBuffer and RustArcPtr have an inner field which we have to fill in with a - // placeholder value. + // RustBuffer and RustArcPtr have an inner field which doesn't affect the rust future + // complete scaffolding function, so we just use a placeholder value here. Some(FfiType::RustArcPtr("".to_owned())), Some(FfiType::RustBuffer(None)), None, - ] - .into_iter() + ]; + + iter::once(self.ffi_rust_future_continuation_callback_set()).chain( + all_possible_return_ffi_types + .into_iter() + .flat_map(|return_type| { + [ + self.ffi_rust_future_poll(return_type.clone()), + self.ffi_rust_future_cancel(return_type.clone()), + self.ffi_rust_future_free(return_type.clone()), + self.ffi_rust_future_complete(return_type), + ] + }), + ) } - /// List all FFI functions definitions for async functionality. - pub fn iter_futures_ffi_function_definitions(&self) -> impl Iterator + '_ { - self.all_possible_return_ffi_types() - .flat_map(|return_type| { - [ - self.ffi_rust_future_poll(return_type.clone()), - self.ffi_rust_future_cancel(return_type.clone()), - self.ffi_rust_future_free(return_type.clone()), - self.ffi_rust_future_complete(return_type), - ] + /// The ffi_foreign_executor_callback_set FFI function + /// + /// We only include this in the FFI if the `ForeignExecutor` type is actually used + pub fn ffi_foreign_executor_callback_set(&self) -> Option { + if self.types.contains(&Type::ForeignExecutor) { + Some(FfiFunction { + name: format!("ffi_{}_foreign_executor_callback_set", self.ffi_namespace()), + arguments: vec![FfiArgument { + name: "callback".into(), + type_: FfiType::ForeignExecutorCallback, + }], + return_type: None, + is_async: false, + has_rust_call_status_arg: false, + is_object_free_function: false, }) + } else { + None + } } /// List all API checksums to check @@ -863,8 +778,6 @@ impl ComponentInterface { bail!("Conflicting type definition for \"{}\"", defn.name()); } self.types.add_known_types(defn.iter_types())?; - defn.throws_name() - .map(|n| self.errors.insert(n.to_string())); self.functions.push(defn); Ok(()) @@ -876,8 +789,6 @@ impl ComponentInterface { let defn: Constructor = meta.into(); self.types.add_known_types(defn.iter_types())?; - defn.throws_name() - .map(|n| self.errors.insert(n.to_string())); object.constructors.push(defn); Ok(()) @@ -889,9 +800,6 @@ impl ComponentInterface { .ok_or_else(|| anyhow!("add_method_meta: object {} not found", &method.object_name))?; self.types.add_known_types(method.iter_types())?; - method - .throws_name() - .map(|n| self.errors.insert(n.to_string())); method.object_impl = object.imp; object.methods.push(method); Ok(()) @@ -917,6 +825,10 @@ impl ComponentInterface { Ok(()) } + pub(super) fn note_name_used_as_error(&mut self, name: &str) { + self.errors.insert(name.to_string()); + } + pub fn is_name_used_as_error(&self, name: &str) -> bool { self.errors.contains(name) } @@ -944,9 +856,6 @@ impl ComponentInterface { self.callback_interface_throws_types.insert(error.clone()); } self.types.add_known_types(method.iter_types())?; - method - .throws_name() - .map(|n| self.errors.insert(n.to_string())); cbi.methods.push(method); } else { self.add_method_meta(meta)?; @@ -971,6 +880,31 @@ impl ComponentInterface { bail!("Conflicting type definition for \"{}\"", f.name()); } } + + for ty in self.iter_types() { + match ty { + Type::Object { name, .. } => { + ensure!( + self.objects.iter().any(|o| o.name == *name), + "Object `{name}` has no definition" + ); + } + Type::Record { name, .. } => { + ensure!( + self.records.contains_key(name), + "Record `{name}` has no definition", + ); + } + Type::Enum { name, .. } => { + ensure!( + self.enums.contains_key(name), + "Enum `{name}` has no definition", + ); + } + _ => {} + } + } + Ok(()) } @@ -1113,7 +1047,7 @@ fn throws_name(throws: &Option) -> Option<&str> { // Type has no `name()` method, just `canonical_name()` which isn't what we want. match throws { None => None, - Some(Type::Enum { name, .. }) | Some(Type::Object { name, .. }) => Some(name), + Some(Type::Enum { name, .. }) => Some(name), _ => panic!("unknown throw type: {throws:?}"), } } @@ -1155,50 +1089,35 @@ mod test { let err = ComponentInterface::from_webidl(UDL2, "crate_name").unwrap_err(); assert_eq!( err.to_string(), - "Mismatching definition for enum `Testing`! -existing definition: Enum { + "Mismatching definition for enum `Testing`!\nexisting definition: Enum { name: \"Testing\", module_path: \"crate_name\", - discr_type: None, variants: [ Variant { name: \"one\", - discr: None, fields: [], - docstring: None, }, Variant { name: \"two\", - discr: None, fields: [], - docstring: None, }, ], flat: true, - non_exhaustive: false, - docstring: None, }, new definition: Enum { name: \"Testing\", module_path: \"crate_name\", - discr_type: None, variants: [ Variant { name: \"three\", - discr: None, fields: [], - docstring: None, }, Variant { name: \"four\", - discr: None, fields: [], - docstring: None, }, ], flat: true, - non_exhaustive: false, - docstring: None, }", ); @@ -1312,25 +1231,4 @@ new definition: Enum { imp: ObjectImpl::Struct, })); } - - #[test] - fn test_docstring_namespace() { - const UDL: &str = r#" - /// informative docstring - namespace test{}; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!(ci.namespace_docstring().unwrap(), "informative docstring"); - } - - #[test] - fn test_multiline_docstring() { - const UDL: &str = r#" - /// informative - /// docstring - namespace test{}; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!(ci.namespace_docstring().unwrap(), "informative\ndocstring"); - } } diff --git a/third_party/rust/uniffi_bindgen/src/interface/object.rs b/third_party/rust/uniffi_bindgen/src/interface/object.rs index 2b86e54a4513..942032b3c6c0 100644 --- a/third_party/rust/uniffi_bindgen/src/interface/object.rs +++ b/third_party/rust/uniffi_bindgen/src/interface/object.rs @@ -57,11 +57,12 @@ //! # Ok::<(), anyhow::Error>(()) //! ``` +use std::iter; + use anyhow::Result; use uniffi_meta::Checksum; -use super::callbacks; -use super::ffi::{FfiArgument, FfiCallbackFunction, FfiFunction, FfiStruct, FfiType}; +use super::ffi::{FfiArgument, FfiFunction, FfiType}; use super::function::{Argument, Callable}; use super::{AsType, ObjectImpl, Type, TypeIterator}; @@ -91,24 +92,14 @@ pub struct Object { // a regular method (albeit with a generated name) // XXX - this should really be a HashSet, but not enough transient types support hash to make it worthwhile now. pub(super) uniffi_traits: Vec, - // We don't include the FfiFuncs in the hash calculation, because: + // We don't include the FfiFunc in the hash calculation, because: // - it is entirely determined by the other fields, // so excluding it is safe. // - its `name` property includes a checksum derived from the very // hash value we're trying to calculate here, so excluding it // avoids a weird circular dependency in the calculation. - - // FFI function to clone a pointer for this object - #[checksum_ignore] - pub(super) ffi_func_clone: FfiFunction, - // FFI function to free a pointer for this object #[checksum_ignore] pub(super) ffi_func_free: FfiFunction, - // Ffi function to initialize the foreign callback for trait interfaces - #[checksum_ignore] - pub(super) ffi_init_callback: Option, - #[checksum_ignore] - pub(super) docstring: Option, } impl Object { @@ -127,18 +118,6 @@ impl Object { &self.imp } - pub fn is_trait_interface(&self) -> bool { - self.imp.is_trait_interface() - } - - pub fn has_callback_interface(&self) -> bool { - self.imp.has_callback_interface() - } - - pub fn has_async_method(&self) -> bool { - self.methods.iter().any(Method::is_async) - } - pub fn constructors(&self) -> Vec<&Constructor> { self.constructors.iter().collect() } @@ -172,28 +151,12 @@ impl Object { self.uniffi_traits.iter().collect() } - pub fn ffi_object_clone(&self) -> &FfiFunction { - &self.ffi_func_clone - } - pub fn ffi_object_free(&self) -> &FfiFunction { &self.ffi_func_free } - pub fn ffi_init_callback(&self) -> &FfiFunction { - self.ffi_init_callback - .as_ref() - .unwrap_or_else(|| panic!("No ffi_init_callback set for {}", &self.name)) - } - - pub fn docstring(&self) -> Option<&str> { - self.docstring.as_deref() - } - pub fn iter_ffi_function_definitions(&self) -> impl Iterator { - [&self.ffi_func_clone, &self.ffi_func_free] - .into_iter() - .chain(&self.ffi_init_callback) + iter::once(&self.ffi_func_free) .chain(self.constructors.iter().map(|f| &f.ffi_func)) .chain(self.methods.iter().map(|f| &f.ffi_func)) .chain( @@ -210,26 +173,13 @@ impl Object { } pub fn derive_ffi_funcs(&mut self) -> Result<()> { - assert!(!self.ffi_func_clone.name().is_empty()); assert!(!self.ffi_func_free.name().is_empty()); - self.ffi_func_clone.arguments = vec![FfiArgument { - name: "ptr".to_string(), - type_: FfiType::RustArcPtr(self.name.to_string()), - }]; - self.ffi_func_clone.return_type = Some(FfiType::RustArcPtr(self.name.to_string())); self.ffi_func_free.arguments = vec![FfiArgument { name: "ptr".to_string(), type_: FfiType::RustArcPtr(self.name.to_string()), }]; self.ffi_func_free.return_type = None; self.ffi_func_free.is_object_free_function = true; - if self.has_callback_interface() { - self.ffi_init_callback = Some(FfiFunction::callback_init( - &self.module_path, - &self.name, - callbacks::vtable_name(&self.name), - )); - } for cons in self.constructors.iter_mut() { cons.derive_ffi_func(); @@ -244,41 +194,6 @@ impl Object { Ok(()) } - /// For trait interfaces, FfiCallbacks to define for our methods, otherwise an empty vec. - pub fn ffi_callbacks(&self) -> Vec { - if self.is_trait_interface() { - callbacks::ffi_callbacks(&self.name, &self.methods) - } else { - vec![] - } - } - - /// For trait interfaces, the VTable FFI type - pub fn vtable(&self) -> Option { - self.is_trait_interface() - .then(|| FfiType::Struct(callbacks::vtable_name(&self.name))) - } - - /// For trait interfaces, the VTable struct to define. Otherwise None. - pub fn vtable_definition(&self) -> Option { - self.is_trait_interface() - .then(|| callbacks::vtable_struct(&self.name, &self.methods)) - } - - /// Vec of (ffi_callback_name, method) pairs - pub fn vtable_methods(&self) -> Vec<(FfiCallbackFunction, &Method)> { - self.methods - .iter() - .enumerate() - .map(|(i, method)| { - ( - callbacks::method_ffi_callback(&self.name, method, i), - method, - ) - }) - .collect() - } - pub fn iter_types(&self) -> TypeIterator<'_> { Box::new( self.methods @@ -303,7 +218,6 @@ impl AsType for Object { impl From for Object { fn from(meta: uniffi_meta::ObjectMetadata) -> Self { - let ffi_clone_name = meta.clone_ffi_symbol_name(); let ffi_free_name = meta.free_ffi_symbol_name(); Object { module_path: meta.module_path, @@ -312,16 +226,10 @@ impl From for Object { constructors: Default::default(), methods: Default::default(), uniffi_traits: Default::default(), - ffi_func_clone: FfiFunction { - name: ffi_clone_name, - ..Default::default() - }, ffi_func_free: FfiFunction { name: ffi_free_name, ..Default::default() }, - ffi_init_callback: None, - docstring: meta.docstring.clone(), } } } @@ -355,7 +263,6 @@ pub struct Constructor { pub(super) name: String, pub(super) object_name: String, pub(super) object_module_path: String, - pub(super) is_async: bool, pub(super) arguments: Vec, // We don't include the FFIFunc in the hash calculation, because: // - it is entirely determined by the other fields, @@ -365,8 +272,6 @@ pub struct Constructor { // avoids a weird circular dependency in the calculation. #[checksum_ignore] pub(super) ffi_func: FfiFunction, - #[checksum_ignore] - pub(super) docstring: Option, pub(super) throws: Option, pub(super) checksum_fn_name: String, // Force a checksum value, or we'll fallback to the trait. @@ -411,20 +316,14 @@ impl Constructor { self.throws.as_ref() } - pub fn docstring(&self) -> Option<&str> { - self.docstring.as_deref() - } - pub fn is_primary_constructor(&self) -> bool { self.name == "new" } fn derive_ffi_func(&mut self) { assert!(!self.ffi_func.name().is_empty()); - self.ffi_func.init( - Some(FfiType::RustArcPtr(self.object_name.clone())), - self.arguments.iter().map(Into::into), - ); + self.ffi_func.arguments = self.arguments.iter().map(Into::into).collect(); + self.ffi_func.return_type = Some(FfiType::RustArcPtr(self.object_name.clone())); } pub fn iter_types(&self) -> TypeIterator<'_> { @@ -440,17 +339,14 @@ impl From for Constructor { let ffi_func = FfiFunction { name: ffi_name, - is_async: meta.is_async, ..FfiFunction::default() }; Self { name: meta.name, object_name: meta.self_name, - is_async: meta.is_async, object_module_path: meta.module_path, arguments, ffi_func, - docstring: meta.docstring.clone(), throws: meta.throws.map(Into::into), checksum_fn_name, checksum: meta.checksum, @@ -479,8 +375,6 @@ pub struct Method { // avoids a weird circular dependency in the calculation. #[checksum_ignore] pub(super) ffi_func: FfiFunction, - #[checksum_ignore] - pub(super) docstring: Option, pub(super) throws: Option, pub(super) takes_self_by_arc: bool, pub(super) checksum_fn_name: String, @@ -551,10 +445,6 @@ impl Method { self.throws.as_ref() } - pub fn docstring(&self) -> Option<&str> { - self.docstring.as_deref() - } - pub fn takes_self_by_arc(&self) -> bool { self.takes_self_by_arc } @@ -576,11 +466,6 @@ impl Method { .chain(self.return_type.iter().flat_map(Type::iter_types)), ) } - - /// For async callback interface methods, the FFI struct to pass to the completion function. - pub fn foreign_future_ffi_result_struct(&self) -> FfiStruct { - callbacks::foreign_future_ffi_result_struct(self.return_type.as_ref().map(FfiType::from)) - } } impl From for Method { @@ -606,7 +491,6 @@ impl From for Method { arguments, return_type, ffi_func, - docstring: meta.docstring.clone(), throws: meta.throws.map(Into::into), takes_self_by_arc: meta.takes_self_by_arc, checksum_fn_name, @@ -619,22 +503,19 @@ impl From for Method { fn from(meta: uniffi_meta::TraitMethodMetadata) -> Self { let ffi_name = meta.ffi_symbol_name(); let checksum_fn_name = meta.checksum_symbol_name(); - let is_async = meta.is_async; let return_type = meta.return_type.map(Into::into); let arguments = meta.inputs.into_iter().map(Into::into).collect(); let ffi_func = FfiFunction { name: ffi_name, - is_async, ..FfiFunction::default() }; Self { name: meta.name, object_name: meta.trait_name, object_module_path: meta.module_path, - is_async, + is_async: false, arguments, return_type, - docstring: meta.docstring.clone(), throws: meta.throws.map(Into::into), takes_self_by_arc: meta.takes_self_by_arc, checksum_fn_name, @@ -702,7 +583,7 @@ impl Callable for Constructor { } fn is_async(&self) -> bool { - self.is_async + false } } @@ -722,10 +603,6 @@ impl Callable for Method { fn is_async(&self) -> bool { self.is_async } - - fn takes_self(&self) -> bool { - true - } } #[cfg(test)] @@ -893,62 +770,4 @@ mod test { "Trait interfaces can not have constructors: \"new\"" ); } - - #[test] - fn test_docstring_object() { - const UDL: &str = r#" - namespace test{}; - /// informative docstring - interface Testing { }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_object_definition("Testing") - .unwrap() - .docstring() - .unwrap(), - "informative docstring" - ); - } - - #[test] - fn test_docstring_constructor() { - const UDL: &str = r#" - namespace test{}; - interface Testing { - /// informative docstring - constructor(); - }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_object_definition("Testing") - .unwrap() - .primary_constructor() - .unwrap() - .docstring() - .unwrap(), - "informative docstring" - ); - } - - #[test] - fn test_docstring_method() { - const UDL: &str = r#" - namespace test{}; - interface Testing { - /// informative docstring - void testing(); - }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_object_definition("Testing") - .unwrap() - .get_method("testing") - .docstring() - .unwrap(), - "informative docstring" - ); - } } diff --git a/third_party/rust/uniffi_bindgen/src/interface/record.rs b/third_party/rust/uniffi_bindgen/src/interface/record.rs index e9a600418968..17d3774a49d7 100644 --- a/third_party/rust/uniffi_bindgen/src/interface/record.rs +++ b/third_party/rust/uniffi_bindgen/src/interface/record.rs @@ -60,8 +60,6 @@ pub struct Record { pub(super) name: String, pub(super) module_path: String, pub(super) fields: Vec, - #[checksum_ignore] - pub(super) docstring: Option, } impl Record { @@ -73,17 +71,9 @@ impl Record { &self.fields } - pub fn docstring(&self) -> Option<&str> { - self.docstring.as_deref() - } - pub fn iter_types(&self) -> TypeIterator<'_> { Box::new(self.fields.iter().flat_map(Field::iter_types)) } - - pub fn has_fields(&self) -> bool { - !self.fields.is_empty() - } } impl AsType for Record { @@ -107,7 +97,6 @@ impl TryFrom for Record { .into_iter() .map(TryInto::try_into) .collect::>()?, - docstring: meta.docstring.clone(), }) } } @@ -118,8 +107,6 @@ pub struct Field { pub(super) name: String, pub(super) type_: Type, pub(super) default: Option, - #[checksum_ignore] - pub(super) docstring: Option, } impl Field { @@ -131,10 +118,6 @@ impl Field { self.default.as_ref() } - pub fn docstring(&self) -> Option<&str> { - self.docstring.as_deref() - } - pub fn iter_types(&self) -> TypeIterator<'_> { self.type_.iter_types() } @@ -157,7 +140,6 @@ impl TryFrom for Field { name, type_, default, - docstring: meta.docstring.clone(), }) } } @@ -245,39 +227,4 @@ mod test { .iter_types() .any(|t| matches!(t, Type::Record { name, .. } if name == "Testing"))); } - - #[test] - fn test_docstring_record() { - const UDL: &str = r#" - namespace test{}; - /// informative docstring - dictionary Testing { }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_record_definition("Testing") - .unwrap() - .docstring() - .unwrap(), - "informative docstring" - ); - } - - #[test] - fn test_docstring_record_field() { - const UDL: &str = r#" - namespace test{}; - dictionary Testing { - /// informative docstring - i32 testing; - }; - "#; - let ci = ComponentInterface::from_webidl(UDL, "crate_name").unwrap(); - assert_eq!( - ci.get_record_definition("Testing").unwrap().fields()[0] - .docstring() - .unwrap(), - "informative docstring" - ); - } } diff --git a/third_party/rust/uniffi_bindgen/src/interface/universe.rs b/third_party/rust/uniffi_bindgen/src/interface/universe.rs index 70bc61f8a9fa..e69d86e44faf 100644 --- a/third_party/rust/uniffi_bindgen/src/interface/universe.rs +++ b/third_party/rust/uniffi_bindgen/src/interface/universe.rs @@ -25,7 +25,6 @@ pub use uniffi_meta::{AsType, ExternalKind, NamespaceMetadata, ObjectImpl, Type, pub(crate) struct TypeUniverse { /// The unique prefixes that we'll use for namespacing when exposing this component's API. pub namespace: NamespaceMetadata, - pub namespace_docstring: Option, // Named type definitions (including aliases). type_definitions: HashMap, @@ -84,6 +83,9 @@ impl TypeUniverse { Type::Bytes => self.add_type_definition("bytes", type_)?, Type::Timestamp => self.add_type_definition("timestamp", type_)?, Type::Duration => self.add_type_definition("duration", type_)?, + Type::ForeignExecutor => { + self.add_type_definition("ForeignExecutor", type_)?; + } Type::Object { name, .. } | Type::Record { name, .. } | Type::Enum { name, .. } @@ -116,7 +118,6 @@ impl TypeUniverse { Ok(()) } - #[cfg(test)] /// Check if a [Type] is present pub fn contains(&self, type_: &Type) -> bool { self.all_known_types.contains(type_) diff --git a/third_party/rust/uniffi_bindgen/src/lib.rs b/third_party/rust/uniffi_bindgen/src/lib.rs index dfc90b32a6c1..019b24022fd3 100644 --- a/third_party/rust/uniffi_bindgen/src/lib.rs +++ b/third_party/rust/uniffi_bindgen/src/lib.rs @@ -58,8 +58,9 @@ //! //! ### 3) Generate and include component scaffolding from the UDL file //! -//! Add to your crate `uniffi_build` under `[build-dependencies]`, -//! then add a `build.rs` script to your crate and have it call `uniffi_build::generate_scaffolding` +//! First you will need to install `uniffi-bindgen` on your system using `cargo install uniffi_bindgen`. +//! Then add to your crate `uniffi_build` under `[build-dependencies]`. +//! Finally, add a `build.rs` script to your crate and have it call `uniffi_build::generate_scaffolding` //! to process your `.udl` file. This will generate some Rust code to be included in the top-level source //! code of your crate. If your UDL file is named `example.udl`, then your build script would call: //! @@ -76,13 +77,12 @@ //! //! ### 4) Generate foreign language bindings for the library //! -//! You will need ensure a local `uniffi-bindgen` - see -//! This utility provides a command-line tool that can produce code to +//! The `uniffi-bindgen` utility provides a command-line tool that can produce code to //! consume the Rust library in any of several supported languages. //! It is done by calling (in kotlin for example): //! //! ```text -//! cargo run --bin -p uniffi-bindgen --language kotlin ./src/example.udl +//! uniffi-bindgen --language kotlin ./src/example.udl //! ``` //! //! This will produce a file `example.kt` in the same directory as the .udl file, containing kotlin bindings @@ -160,16 +160,15 @@ pub trait BindingGenerator: Sized { ci: &ComponentInterface, config: &Self::Config, out_dir: &Utf8Path, - try_format_code: bool, ) -> Result<()>; /// Check if `library_path` used by library mode is valid for this generator fn check_library_path(&self, library_path: &Utf8Path, cdylib_name: Option<&str>) -> Result<()>; } -pub struct BindingGeneratorDefault { - pub target_languages: Vec, - pub try_format_code: bool, +struct BindingGeneratorDefault { + target_languages: Vec, + try_format_code: bool, } impl BindingGenerator for BindingGeneratorDefault { @@ -180,7 +179,6 @@ impl BindingGenerator for BindingGeneratorDefault { ci: &ComponentInterface, config: &Self::Config, out_dir: &Utf8Path, - _try_format_code: bool, ) -> Result<()> { for &language in &self.target_languages { bindings::write_bindings( @@ -221,13 +219,12 @@ impl BindingGenerator for BindingGeneratorDefault { /// - `library_file`: The path to a dynamic library to attempt to extract the definitions from and extend the component interface with. No extensions to component interface occur if it's [`None`] /// - `crate_name`: Override the default crate name that is guessed from UDL file path. pub fn generate_external_bindings( - binding_generator: &T, + binding_generator: T, udl_file: impl AsRef, config_file_override: Option>, out_dir_override: Option>, library_file: Option>, crate_name: Option<&str>, - try_format_code: bool, ) -> Result<()> { let crate_name = crate_name .map(|c| Ok(c.to_string())) @@ -256,7 +253,7 @@ pub fn generate_external_bindings( udl_file.as_ref(), out_dir_override.as_ref().map(|p| p.as_ref()), )?; - binding_generator.write_bindings(&component, &config, &out_dir, try_format_code) + binding_generator.write_bindings(&component, &config, &out_dir) } // Generate the infrastructural Rust code for implementing the UDL interface, @@ -304,23 +301,25 @@ fn generate_component_scaffolding_inner( // Generate the bindings in the target languages that call the scaffolding // Rust code. -pub fn generate_bindings( +pub fn generate_bindings( udl_file: &Utf8Path, config_file_override: Option<&Utf8Path>, - binding_generator: T, + target_languages: Vec, out_dir_override: Option<&Utf8Path>, library_file: Option<&Utf8Path>, crate_name: Option<&str>, try_format_code: bool, ) -> Result<()> { generate_external_bindings( - &binding_generator, + BindingGeneratorDefault { + target_languages, + try_format_code, + }, udl_file, config_file_override, out_dir_override, library_file, crate_name, - try_format_code, ) } @@ -418,53 +417,22 @@ fn format_code_with_rustfmt(path: &Utf8Path) -> Result<()> { Ok(()) } -/// Load TOML from file if the file exists. -fn load_toml_file(source: Option<&Utf8Path>) -> Result> { - if let Some(source) = source { - if source.exists() { - let contents = - fs::read_to_string(source).with_context(|| format!("read file: {:?}", source))?; - return Ok(Some( - toml::de::from_str(&contents) - .with_context(|| format!("parse toml: {:?}", source))?, - )); - } - } - - Ok(None) -} - -/// Load the default `uniffi.toml` config, merge TOML trees with `config_file_override` if specified. fn load_initial_config( crate_root: &Utf8Path, config_file_override: Option<&Utf8Path>, ) -> Result { - let mut config = load_toml_file(Some(crate_root.join("uniffi.toml").as_path())) - .context("default config")? - .unwrap_or(toml::value::Table::default()); - - let override_config = load_toml_file(config_file_override).context("override config")?; - if let Some(override_config) = override_config { - merge_toml(&mut config, override_config); - } - - Ok(toml::Value::from(config).try_into()?) -} - -fn merge_toml(a: &mut toml::value::Table, b: toml::value::Table) { - for (key, value) in b.into_iter() { - match a.get_mut(&key) { - Some(existing_value) => match (existing_value, value) { - (toml::Value::Table(ref mut t0), toml::Value::Table(t1)) => { - merge_toml(t0, t1); - } - (v, value) => *v = value, - }, - None => { - a.insert(key, value); - } + let path = match config_file_override { + Some(cfg) => Some(cfg.to_owned()), + None => crate_root.join("uniffi.toml").canonicalize_utf8().ok(), + }; + let toml_config = match path { + Some(path) => { + let contents = fs::read_to_string(path).context("Failed to read config file")?; + toml::de::from_str(&contents)? } - } + None => toml::Value::from(toml::value::Table::default()), + }; + Ok(toml_config.try_into()?) } #[derive(Debug, Clone, Default, Serialize, Deserialize)] @@ -548,56 +516,4 @@ mod test { let not_a_crate_root = &this_crate_root.join("src/templates"); assert!(guess_crate_root(¬_a_crate_root.join("src/example.udl")).is_err()); } - - #[test] - fn test_merge_toml() { - let default = r#" - foo = "foo" - bar = "bar" - - [table1] - foo = "foo" - bar = "bar" - "#; - let mut default = toml::de::from_str(default).unwrap(); - - let override_toml = r#" - # update key - bar = "BAR" - # insert new key - baz = "BAZ" - - [table1] - # update key - bar = "BAR" - # insert new key - baz = "BAZ" - - # new table - [table1.table2] - bar = "BAR" - baz = "BAZ" - "#; - let override_toml = toml::de::from_str(override_toml).unwrap(); - - let expected = r#" - foo = "foo" - bar = "BAR" - baz = "BAZ" - - [table1] - foo = "foo" - bar = "BAR" - baz = "BAZ" - - [table1.table2] - bar = "BAR" - baz = "BAZ" - "#; - let expected: toml::value::Table = toml::de::from_str(expected).unwrap(); - - merge_toml(&mut default, override_toml); - - assert_eq!(&expected, &default); - } } diff --git a/third_party/rust/uniffi_bindgen/src/library_mode.rs b/third_party/rust/uniffi_bindgen/src/library_mode.rs index c460c03d9f48..f170ea5e918b 100644 --- a/third_party/rust/uniffi_bindgen/src/library_mode.rs +++ b/third_party/rust/uniffi_bindgen/src/library_mode.rs @@ -16,8 +16,8 @@ /// - UniFFI can figure out the package/module names for each crate, eliminating the external /// package maps. use crate::{ - load_initial_config, macro_metadata, BindingGenerator, BindingsConfig, ComponentInterface, - Result, + bindings::TargetLanguage, load_initial_config, macro_metadata, BindingGenerator, + BindingGeneratorDefault, BindingsConfig, ComponentInterface, Result, }; use anyhow::{bail, Context}; use camino::Utf8Path; @@ -33,21 +33,21 @@ use uniffi_meta::{ /// Generate foreign bindings /// /// Returns the list of sources used to generate the bindings, in no particular order. -pub fn generate_bindings( +pub fn generate_bindings( library_path: &Utf8Path, crate_name: Option, - binding_generator: &T, - config_file_override: Option<&Utf8Path>, + target_languages: &[TargetLanguage], out_dir: &Utf8Path, try_format_code: bool, -) -> Result>> { +) -> Result>> { generate_external_bindings( - binding_generator, + BindingGeneratorDefault { + target_languages: target_languages.into(), + try_format_code, + }, library_path, - crate_name.clone(), - config_file_override, + crate_name, out_dir, - try_format_code, ) } @@ -55,12 +55,10 @@ pub fn generate_bindings( /// /// Returns the list of sources used to generate the bindings, in no particular order. pub fn generate_external_bindings( - binding_generator: &T, + binding_generator: T, library_path: &Utf8Path, crate_name: Option, - config_file_override: Option<&Utf8Path>, out_dir: &Utf8Path, - try_format_code: bool, ) -> Result>> { let cargo_metadata = MetadataCommand::new() .exec() @@ -68,12 +66,7 @@ pub fn generate_external_bindings( let cdylib_name = calc_cdylib_name(library_path); binding_generator.check_library_path(library_path, cdylib_name)?; - let mut sources = find_sources( - &cargo_metadata, - library_path, - cdylib_name, - config_file_override, - )?; + let mut sources = find_sources(&cargo_metadata, library_path, cdylib_name)?; for i in 0..sources.len() { // Partition up the sources list because we're eventually going to call // `update_from_dependency_configs()` which requires an exclusive reference to one source and @@ -108,7 +101,7 @@ pub fn generate_external_bindings( } for source in sources.iter() { - binding_generator.write_bindings(&source.ci, &source.config, out_dir, try_format_code)?; + binding_generator.write_bindings(&source.ci, &source.config, out_dir)?; } Ok(sources) @@ -125,10 +118,10 @@ pub struct Source { // If `library_path` is a C dynamic library, return its name pub fn calc_cdylib_name(library_path: &Utf8Path) -> Option<&str> { - let cdylib_extensions = [".so", ".dll", ".dylib"]; + let cdylib_extentions = [".so", ".dll", ".dylib"]; let filename = library_path.file_name()?; let filename = filename.strip_prefix("lib").unwrap_or(filename); - for ext in cdylib_extensions { + for ext in cdylib_extentions { if let Some(f) = filename.strip_suffix(ext) { return Some(f); } @@ -140,7 +133,6 @@ fn find_sources( cargo_metadata: &cargo_metadata::Metadata, library_path: &Utf8Path, cdylib_name: Option<&str>, - config_file_override: Option<&Utf8Path>, ) -> Result>> { let items = macro_metadata::extract_from_library(library_path)?; let mut metadata_groups = create_metadata_groups(&items); @@ -186,7 +178,7 @@ fn find_sources( ci.add_metadata(metadata)?; }; ci.add_metadata(group)?; - let mut config = load_initial_config::(crate_root, config_file_override)?; + let mut config = load_initial_config::(crate_root, None)?; if let Some(cdylib_name) = cdylib_name { config.update_from_cdylib_name(cdylib_name); } diff --git a/third_party/rust/uniffi_bindgen/src/macro_metadata/ci.rs b/third_party/rust/uniffi_bindgen/src/macro_metadata/ci.rs index 69fad1980e90..7ce6c3a70ba8 100644 --- a/third_party/rust/uniffi_bindgen/src/macro_metadata/ci.rs +++ b/third_party/rust/uniffi_bindgen/src/macro_metadata/ci.rs @@ -4,7 +4,9 @@ use crate::interface::{CallbackInterface, ComponentInterface, Enum, Record, Type}; use anyhow::{bail, Context}; -use uniffi_meta::{create_metadata_groups, group_metadata, EnumMetadata, Metadata, MetadataGroup}; +use uniffi_meta::{ + create_metadata_groups, group_metadata, EnumMetadata, ErrorMetadata, Metadata, MetadataGroup, +}; /// Add Metadata items to the ComponentInterface /// @@ -96,9 +98,7 @@ fn add_item_to_ci(iface: &mut ComponentInterface, item: Metadata) -> anyhow::Res iface.add_record_definition(record)?; } Metadata::Enum(meta) => { - let flat = meta - .forced_flatness - .unwrap_or_else(|| meta.variants.iter().all(|v| v.fields.is_empty())); + let flat = meta.variants.iter().all(|v| v.fields.is_empty()); add_enum_to_ci(iface, meta, flat)?; } Metadata::Object(meta) => { @@ -117,11 +117,22 @@ fn add_item_to_ci(iface: &mut ComponentInterface, item: Metadata) -> anyhow::Res module_path: meta.module_path.clone(), name: meta.name.clone(), })?; - iface.add_callback_interface_definition(CallbackInterface::try_from(meta)?); + iface.add_callback_interface_definition(CallbackInterface::new( + meta.name, + meta.module_path, + )); } Metadata::TraitMethod(meta) => { iface.add_trait_method_meta(meta)?; } + Metadata::Error(meta) => { + iface.note_name_used_as_error(meta.name()); + match meta { + ErrorMetadata::Enum { enum_, is_flat } => { + add_enum_to_ci(iface, enum_, is_flat)?; + } + }; + } Metadata::CustomType(meta) => { iface.types.add_known_type(&Type::Custom { module_path: meta.module_path.clone(), diff --git a/third_party/rust/uniffi_bindgen/src/macro_metadata/extract.rs b/third_party/rust/uniffi_bindgen/src/macro_metadata/extract.rs index 6d440919f16b..25b5ef17ba27 100644 --- a/third_party/rust/uniffi_bindgen/src/macro_metadata/extract.rs +++ b/third_party/rust/uniffi_bindgen/src/macro_metadata/extract.rs @@ -30,7 +30,7 @@ fn extract_from_bytes(file_data: &[u8]) -> anyhow::Result> { Object::PE(pe) => extract_from_pe(pe, file_data), Object::Mach(mach) => extract_from_mach(mach, file_data), Object::Archive(archive) => extract_from_archive(archive, file_data), - _ => bail!("Unknown library format"), + Object::Unknown(_) => bail!("Unknown library format"), } } diff --git a/third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs b/third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs index 7fd81831aaf6..f3759cf6faff 100644 --- a/third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs +++ b/third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs @@ -45,6 +45,7 @@ mod filters { format!("std::sync::Arc<{}>", imp.rust_name_for(name)) } Type::CallbackInterface { name, .. } => format!("Box"), + Type::ForeignExecutor => "::uniffi::ForeignExecutor".into(), Type::Optional { inner_type } => { format!("std::option::Option<{}>", type_rs(inner_type)?) } @@ -63,12 +64,41 @@ mod filters { kind: ExternalKind::Interface, .. } => format!("::std::sync::Arc"), + Type::External { name, .. } => format!("r#{name}"), + }) + } + + // Map a type to Rust code that specifies the FfiConverter implementation. + // + // This outputs something like `>` + pub fn ffi_trait(type_: &Type, trait_name: &str) -> Result { + Ok(match type_ { Type::External { name, - kind: ExternalKind::Trait, + kind: ExternalKind::Interface, .. - } => format!("::std::sync::Arc"), - Type::External { name, .. } => format!("r#{name}"), + } => { + format!("<::std::sync::Arc as ::uniffi::{trait_name}>") + } + _ => format!( + "<{} as ::uniffi::{trait_name}>", + type_rs(type_)? + ), + }) + } + + pub fn return_type(callable: &T) -> Result { + let return_type = match callable.return_type() { + Some(t) => type_rs(&t)?, + None => "()".to_string(), + }; + match callable.throws_type() { + Some(t) => type_rs(&t)?, + None => "()".to_string(), + }; + Ok(match callable.throws_type() { + Some(e) => format!("::std::result::Result<{return_type}, {}>", type_rs(&e)?), + None => return_type, }) } diff --git a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/CallbackInterfaceTemplate.rs b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/CallbackInterfaceTemplate.rs dissimilarity index 83% index 658f4c8de527..64c69e4d8e87 100644 --- a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/CallbackInterfaceTemplate.rs +++ b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/CallbackInterfaceTemplate.rs @@ -1,17 +1,82 @@ -#[::uniffi::export_for_udl(callback_interface)] -pub trait r#{{ cbi.name() }} { - {%- for meth in cbi.methods() %} - fn r#{{ meth.name() }}( - {% if meth.takes_self_by_arc()%}self: Arc{% else %}&self{% endif %}, - {%- for arg in meth.arguments() %} - r#{{ arg.name() }}: {% if arg.by_ref() %}&{% endif %}{{ arg.as_type().borrow()|type_rs }}, - {%- endfor %} - ) - {%- match (meth.return_type(), meth.throws_type()) %} - {%- when (Some(return_type), None) %} -> {{ return_type|type_rs }}; - {%- when (Some(return_type), Some(error_type)) %} -> ::std::result::Result::<{{ return_type|type_rs }}, {{ error_type|type_rs }}>; - {%- when (None, Some(error_type)) %} -> ::std::result::Result::<(), {{ error_type|type_rs }}>; - {%- when (None, None) %}; - {%- endmatch %} - {% endfor %} -} +{# +// For each Callback Interface definition, we assume that there is a corresponding trait defined in Rust client code. +// If the UDL callback interface and Rust trait's methods don't match, the Rust compiler will complain. +// We generate: +// * an init function to accept that `ForeignCallback` from the foreign language, and stores it. +// * a holder for a `ForeignCallback`, of type `uniffi::ForeignCallbackInternals`. +// * a proxy `struct` which implements the `trait` that the Callback Interface corresponds to. This +// is the object that client code interacts with. +// - for each method, arguments will be packed into a `RustBuffer` and sent over the `ForeignCallback` to be +// unpacked and called. The return value is packed into another `RustBuffer` and sent back to Rust. +// - a `Drop` `impl`, which tells the foreign language to forget about the real callback object. +#} +{% let trait_name = cbi.name() -%} +{% let trait_impl = format!("UniFFICallbackHandler{}", trait_name) %} +{% let foreign_callback_internals = format!("foreign_callback_{}_internals", trait_name)|upper -%} + +// Register a foreign callback for getting across the FFI. +#[doc(hidden)] +static {{ foreign_callback_internals }}: uniffi::ForeignCallbackInternals = uniffi::ForeignCallbackInternals::new(); + +#[doc(hidden)] +#[no_mangle] +pub extern "C" fn {{ cbi.ffi_init_callback().name() }}(callback: uniffi::ForeignCallback, _: &mut uniffi::RustCallStatus) { + {{ foreign_callback_internals }}.set_callback(callback); + // The call status should be initialized to CALL_SUCCESS, so no need to modify it. +} + +// Make an implementation which will shell out to the foreign language. +#[doc(hidden)] +#[derive(Debug)] +struct {{ trait_impl }} { + handle: u64 +} + +impl {{ trait_impl }} { + fn new(handle: u64) -> Self { + Self { handle } + } +} + +impl Drop for {{ trait_impl }} { + fn drop(&mut self) { + {{ foreign_callback_internals }}.invoke_callback::<(), crate::UniFfiTag>( + self.handle, uniffi::IDX_CALLBACK_FREE, Default::default() + ) + } +} + +uniffi::deps::static_assertions::assert_impl_all!({{ trait_impl }}: Send); + +impl r#{{ trait_name }} for {{ trait_impl }} { + {%- for meth in cbi.methods() %} + + {#- Method declaration #} + fn r#{{ meth.name() -}} + ({% call rs::arg_list_decl_with_prefix("&self", meth) %}) + {%- match (meth.return_type(), meth.throws_type()) %} + {%- when (Some(return_type), None) %} -> {{ return_type.borrow()|type_rs }} + {%- when (Some(return_type), Some(err)) %} -> ::std::result::Result<{{ return_type.borrow()|type_rs }}, {{ err|type_rs }}> + {%- when (None, Some(err)) %} -> ::std::result::Result<(), {{ err|type_rs }}> + {% else -%} + {%- endmatch -%} { + {#- Method body #} + + {#- Packing args into a RustBuffer #} + {% if meth.arguments().len() == 0 -%} + let args_buf = Vec::new(); + {% else -%} + let mut args_buf = Vec::new(); + {% endif -%} + {%- for arg in meth.arguments() %} + {{ arg.as_type().borrow()|ffi_trait("Lower") }}::write(r#{{ arg.name() }}, &mut args_buf); + {%- endfor -%} + let args_rbuf = uniffi::RustBuffer::from_vec(args_buf); + + {#- Calling into foreign code. #} + {{ foreign_callback_internals }}.invoke_callback::<{{ meth|return_type }}, crate::UniFfiTag>(self.handle, {{ loop.index }}, args_rbuf) + } + {%- endfor %} +} + +::uniffi::scaffolding_ffi_converter_callback_interface!(r#{{ trait_name }}, {{ trait_impl }}); diff --git a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/EnumTemplate.rs b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/EnumTemplate.rs index f918ef2f3a55..6b9f96f2248d 100644 --- a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/EnumTemplate.rs +++ b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/EnumTemplate.rs @@ -1,12 +1,13 @@ {# -// Forward work to `uniffi_macros` This keeps macro-based and UDL-based generated code consistent. +// For each enum declared in the UDL, we assume the caller has provided a corresponding +// rust `enum`. We provide the traits for sending it across the FFI, which will fail to +// compile if the provided struct has a different shape to the one declared in the UDL. +// +// We define a unit-struct to implement the trait to sidestep Rust's orphan rule (ADR-0006). It's +// public so other crates can refer to it via an `[External='crate'] typedef` #} -#[::uniffi::derive_enum_for_udl( - {%- if e.is_non_exhaustive() -%} - non_exhaustive, - {%- endif %} -)] +#[::uniffi::derive_enum_for_udl] enum r#{{ e.name() }} { {%- for variant in e.variants() %} r#{{ variant.name() }} { diff --git a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ErrorTemplate.rs b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ErrorTemplate.rs index 64f48e233497..94538ecaa898 100644 --- a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ErrorTemplate.rs +++ b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ErrorTemplate.rs @@ -1,5 +1,10 @@ {# -// Forward work to `uniffi_macros` This keeps macro-based and UDL-based generated code consistent. +// For each error declared in the UDL, we assume the caller has provided a corresponding +// rust `enum`. We provide the traits for sending it across the FFI, which will fail to +// compile if the provided struct has a different shape to the one declared in the UDL. +// +// We define a unit-struct to implement the trait to sidestep Rust's orphan rule (ADR-0006). It's +// public so other crates can refer to it via an `[External='crate'] typedef` #} #[::uniffi::derive_error_for_udl( @@ -9,9 +14,6 @@ with_try_read, {%- endif %} {%- endif %} - {%- if e.is_non_exhaustive() -%} - non_exhaustive, - {%- endif %} )] enum r#{{ e.name() }} { {%- for variant in e.variants() %} diff --git a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ExternalTypesTemplate.rs b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ExternalTypesTemplate.rs index d67e172cc26f..ade1578897a8 100644 --- a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ExternalTypesTemplate.rs +++ b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ExternalTypesTemplate.rs @@ -10,8 +10,6 @@ ::uniffi::ffi_converter_forward!(r#{{ name }}, ::{{ crate_name|crate_name_rs }}::UniFfiTag, crate::UniFfiTag); {%- when ExternalKind::Interface %} ::uniffi::ffi_converter_arc_forward!(r#{{ name }}, ::{{ crate_name|crate_name_rs }}::UniFfiTag, crate::UniFfiTag); -{%- when ExternalKind::Trait %} -::uniffi::ffi_converter_arc_forward!(dyn r#{{ name }}, ::{{ crate_name|crate_name_rs }}::UniFfiTag, crate::UniFfiTag); {%- endmatch %} {% endif %} {%- endfor %} diff --git a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ObjectTemplate.rs b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ObjectTemplate.rs index e752878af59b..e2445c670d97 100644 --- a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ObjectTemplate.rs +++ b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/ObjectTemplate.rs @@ -1,15 +1,24 @@ -{# -// Forward work to `uniffi_macros` This keeps macro-based and UDL-based generated code consistent. -#} +// For each Object definition, we assume the caller has provided an appropriately-shaped `struct T` +// with an `impl` for each method on the object. We create an `Arc` for "safely" handing out +// references to these structs to foreign language code, and we provide a `pub extern "C"` function +// corresponding to each method. +// +// (Note that "safely" is in "scare quotes" - that's because we use functions on an `Arc` that +// that are inherently unsafe, but the code we generate is safe in practice.) +// +// If the caller's implementation of the struct does not match with the methods or types specified +// in the UDL, then the rust compiler will complain with a (hopefully at least somewhat helpful!) +// error message when processing this generated code. -{%- if obj.is_trait_interface() %} -#[::uniffi::export_for_udl{% if obj.has_callback_interface() %}(with_foreign){% endif %}] +{%- match obj.imp() -%} +{%- when ObjectImpl::Trait %} +#[::uniffi::export_for_udl] pub trait r#{{ obj.name() }} { {%- for meth in obj.methods() %} - {% if meth.is_async() %}async {% endif %}fn r#{{ meth.name() }}( + fn {{ meth.name() }}( {% if meth.takes_self_by_arc()%}self: Arc{% else %}&self{% endif %}, {%- for arg in meth.arguments() %} - r#{{ arg.name() }}: {% if arg.by_ref() %}&{% endif %}{{ arg.as_type().borrow()|type_rs }}, + {{ arg.name() }}: {% if arg.by_ref() %}&{% endif %}{{ arg.as_type().borrow()|type_rs }}, {%- endfor %} ) {%- match (meth.return_type(), meth.throws_type()) %} @@ -20,7 +29,7 @@ pub trait r#{{ obj.name() }} { {%- endmatch %} {% endfor %} } -{%- else %} +{% when ObjectImpl::Struct %} {%- for tm in obj.uniffi_traits() %} {% match tm %} {% when UniffiTrait::Debug { fmt }%} @@ -37,10 +46,9 @@ pub trait r#{{ obj.name() }} { struct {{ obj.rust_name() }} { } {%- for cons in obj.constructors() %} -#[::uniffi::export_for_udl] +#[::uniffi::export_for_udl(constructor)] impl {{ obj.rust_name() }} { - #[uniffi::constructor] - pub {% if cons.is_async() %}async {% endif %}fn r#{{ cons.name() }}( + pub fn r#{{ cons.name() }}( {%- for arg in cons.arguments() %} r#{{ arg.name() }}: {% if arg.by_ref() %}&{% endif %}{{ arg.as_type().borrow()|type_rs }}, {%- endfor %} @@ -60,7 +68,7 @@ impl {{ obj.rust_name() }} { {%- for meth in obj.methods() %} #[::uniffi::export_for_udl] impl {{ obj.rust_name() }} { - pub {% if meth.is_async() %}async {% endif %}fn r#{{ meth.name() }}( + pub fn r#{{ meth.name() }}( {% if meth.takes_self_by_arc()%}self: Arc{% else %}&self{% endif %}, {%- for arg in meth.arguments() %} r#{{ arg.name() }}: {% if arg.by_ref() %}&{% endif %}{{ arg.as_type().borrow()|type_rs }}, @@ -78,4 +86,4 @@ impl {{ obj.rust_name() }} { } {%- endfor %} -{% endif %} +{% endmatch %} diff --git a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/RecordTemplate.rs b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/RecordTemplate.rs index a7affdf7b84a..85e131dd8cf7 100644 --- a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/RecordTemplate.rs +++ b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/RecordTemplate.rs @@ -1,5 +1,11 @@ {# -// Forward work to `uniffi_macros` This keeps macro-based and UDL-based generated code consistent. +// For each record declared in the UDL, we assume the caller has provided a corresponding +// rust `struct` with the declared fields. We provide the traits for sending it across the FFI. +// If the caller's struct does not match the shape and types declared in the UDL then the rust +// compiler will complain with a type error. +// +// We define a unit-struct to implement the trait to sidestep Rust's orphan rule (ADR-0006). It's +// public so other crates can refer to it via an `[External='crate'] typedef` #} #[::uniffi::derive_record_for_udl] diff --git a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/TopLevelFunctionTemplate.rs b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/TopLevelFunctionTemplate.rs index 27f3686b9f62..eeee0f5ee297 100644 --- a/third_party/rust/uniffi_bindgen/src/scaffolding/templates/TopLevelFunctionTemplate.rs +++ b/third_party/rust/uniffi_bindgen/src/scaffolding/templates/TopLevelFunctionTemplate.rs @@ -1,8 +1,5 @@ -{# -// Forward work to `uniffi_macros` This keeps macro-based and UDL-based generated code consistent. -#} #[::uniffi::export_for_udl] -pub {% if func.is_async() %}async {% endif %}fn r#{{ func.name() }}( +pub fn r#{{ func.name() }}( {%- for arg in func.arguments() %} r#{{ arg.name() }}: {% if arg.by_ref() %}&{% endif %}{{ arg.as_type().borrow()|type_rs }}, {%- endfor %} diff --git a/third_party/rust/uniffi_build/.cargo-checksum.json b/third_party/rust/uniffi_build/.cargo-checksum.json index a9005a0f5850..8e585bfa958d 100644 --- a/third_party/rust/uniffi_build/.cargo-checksum.json +++ b/third_party/rust/uniffi_build/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"8fcf43ff5e6c1281a1ee5f9ed796b0f8115bd39ca9ce5b2d0c32e88d9eb2038f","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/lib.rs":"47ff3d1a18456164414af1c20cd5df129401e5257cc15552ecc39afed8970707"},"package":"45cba427aeb7b3a8b54830c4c915079a7a3c62608dd03dddba1d867a8a023eb4"} \ No newline at end of file +{"files":{"Cargo.toml":"a6db989e5a3d597219df0a9c94541130b7db607efd8606043cd1187971020639","src/lib.rs":"47ff3d1a18456164414af1c20cd5df129401e5257cc15552ecc39afed8970707"},"package":"001964dd3682d600084b3aaf75acf9c3426699bc27b65e96bb32d175a31c74e9"} \ No newline at end of file diff --git a/third_party/rust/uniffi_build/Cargo.toml b/third_party/rust/uniffi_build/Cargo.toml index fed51c34ca2b..3fe7ee5cf0d0 100644 --- a/third_party/rust/uniffi_build/Cargo.toml +++ b/third_party/rust/uniffi_build/Cargo.toml @@ -12,12 +12,11 @@ [package] edition = "2021" name = "uniffi_build" -version = "0.27.1" +version = "0.25.3" authors = ["Firefox Sync Team "] description = "a multi-language bindings generator for rust (build script helpers)" homepage = "https://mozilla.github.io/uniffi-rs" documentation = "https://mozilla.github.io/uniffi-rs" -readme = "README.md" keywords = [ "ffi", "bindgen", @@ -32,7 +31,7 @@ version = "1" version = "1.0.8" [dependencies.uniffi_bindgen] -version = "=0.27.1" +version = "=0.25.3" default-features = false [features] diff --git a/third_party/rust/uniffi_build/README.md b/third_party/rust/uniffi_build/README.md deleted file mode 100644 index 64ac3486a3bf..000000000000 --- a/third_party/rust/uniffi_build/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# UniFFI - a multi-language bindings generator for Rust - -UniFFI is a toolkit for building cross-platform software components in Rust. - -For the impatient, see [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/) -or [**the UniFFI examples**](https://github.com/mozilla/uniffi-rs/tree/main/examples#example-uniffi-components). - -By writing your core business logic in Rust and describing its interface in an "object model", -you can use UniFFI to help you: - -* Compile your Rust code into a shared library for use on different target platforms. -* Generate bindings to load and use the library from different target languages. - -You can describe your object model in an [interface definition file](https://mozilla.github.io/uniffi-rs/udl_file_spec.html) -or [by using proc-macros](https://mozilla.github.io/uniffi-rs/proc_macro/index.html). - -UniFFI is currently used extensively by Mozilla in Firefox mobile and desktop browsers; -written once in Rust, auto-generated bindings allow that functionality to be called -from both Kotlin (for Android apps) and Swift (for iOS apps). -It also has a growing community of users shipping various cool things to many users. - -UniFFI comes with support for **Kotlin**, **Swift**, **Python** and **Ruby** with 3rd party bindings available for **C#** and **Golang**. -Additional foreign language bindings can be developed externally and we welcome contributions to list them here. -See [Third-party foreign language bindings](#third-party-foreign-language-bindings). - -## User Guide - -You can read more about using the tool in [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/). - -We consider it ready for production use, but UniFFI is a long way from a 1.0 release with lots of internal work still going on. -We try hard to avoid breaking simple consumers, but more advanced things might break as you upgrade over time. - -### Etymology and Pronunciation - -ˈjuːnɪfaɪ. Pronounced to rhyme with "unify". - -A portmanteau word that also puns with "unify", to signify the joining of one codebase accessed from many languages. - -uni - [Latin ūni-, from ūnus, one] -FFI - [Abbreviation, Foreign Function Interface] - -## Alternative tools - -Other tools we know of which try and solve a similarly shaped problem are: - -* [Diplomat](https://github.com/rust-diplomat/diplomat/) - see our [writeup of - the different approach taken by that tool](docs/diplomat-and-macros.md) -* [Interoptopus](https://github.com/ralfbiedert/interoptopus/) - -(Please open a PR if you think other tools should be listed!) - -## Third-party foreign language bindings - -* [Kotlin Multiplatform support](https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings). The repository contains Kotlin Multiplatform bindings generation for UniFFI, letting you target both JVM and Native. -* [Go bindings](https://github.com/NordSecurity/uniffi-bindgen-go) -* [C# bindings](https://github.com/NordSecurity/uniffi-bindgen-cs) -* [Dart bindings](https://github.com/NiallBunting/uniffi-rs-dart) - -### External resources - -There are a few third-party resources that make it easier to work with UniFFI: - -* [Plugin support for `.udl` files](https://github.com/Lonami/uniffi-dl) for the IDEA platform ([*uniffi-dl* in the JetBrains marketplace](https://plugins.jetbrains.com/plugin/20527-uniffi-dl)). It provides syntax highlighting, code folding, code completion, reference resolution and navigation (among others features) for the [UniFFI Definition Language (UDL)](https://mozilla.github.io/uniffi-rs/). -* [cargo swift](https://github.com/antoniusnaumann/cargo-swift), a cargo plugin to build a Swift Package from Rust code. It provides an init command for setting up a UniFFI crate and a package command for building a Swift package from Rust code - without the need for additional configuration or build scripts. -* [Cargo NDK Gradle Plugin](https://github.com/willir/cargo-ndk-android-gradle) allows you to build Rust code using [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk), which generally makes Android library builds less painful. -* [`uniffi-starter`](https://github.com/ianthetechie/uniffi-starter) is a minimal project demonstrates a wide range of UniFFI in a complete project in a compact manner. It includes a full Android library build process, an XCFramework generation script, and example Swift package structure. - -(Please open a PR if you think other resources should be listed!) - -## Contributing - -If this tool sounds interesting to you, please help us develop it! You can: - -* View the [contributor guidelines](./docs/contributing.md). -* File or work on [issues](https://github.com/mozilla/uniffi-rs/issues) here in GitHub. -* Join discussions in the [#uniffi:mozilla.org](https://matrix.to/#/#uniffi:mozilla.org) - room on Matrix. - -## Code of Conduct - -This project is governed by Mozilla's [Community Participation Guidelines](./CODE_OF_CONDUCT.md). diff --git a/third_party/rust/uniffi_checksum_derive/.cargo-checksum.json b/third_party/rust/uniffi_checksum_derive/.cargo-checksum.json index 5e211378a08a..9df6eba7b4ab 100644 --- a/third_party/rust/uniffi_checksum_derive/.cargo-checksum.json +++ b/third_party/rust/uniffi_checksum_derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"da89504b9007c2a1ea0e498a2e8ec6baeb0ff7391363cd9007e383247637792c","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/lib.rs":"44d2e2c595b14d33d16c71dfe4ef42ad0b9e010a878ee2ec49c2e929d60275ba"},"package":"ae7e5a6c33b1dec3f255f57ec0b6af0f0b2bb3021868be1d5eec7a38e2905ebc"} \ No newline at end of file +{"files":{"Cargo.toml":"028104be15a1d73a8ca192a30865b26827344808a95b21e3798e4c9406ebc4f1","src/lib.rs":"44d2e2c595b14d33d16c71dfe4ef42ad0b9e010a878ee2ec49c2e929d60275ba"},"package":"55137c122f712d9330fd985d66fa61bdc381752e89c35708c13ce63049a3002c"} \ No newline at end of file diff --git a/third_party/rust/uniffi_checksum_derive/Cargo.toml b/third_party/rust/uniffi_checksum_derive/Cargo.toml index 681c8846e199..a3c4ed7ca342 100644 --- a/third_party/rust/uniffi_checksum_derive/Cargo.toml +++ b/third_party/rust/uniffi_checksum_derive/Cargo.toml @@ -12,12 +12,11 @@ [package] edition = "2021" name = "uniffi_checksum_derive" -version = "0.27.1" +version = "0.25.3" authors = ["Firefox Sync Team "] description = "a multi-language bindings generator for rust (checksum custom derive)" homepage = "https://mozilla.github.io/uniffi-rs" documentation = "https://mozilla.github.io/uniffi-rs" -readme = "README.md" keywords = [ "ffi", "bindgen", diff --git a/third_party/rust/uniffi_checksum_derive/README.md b/third_party/rust/uniffi_checksum_derive/README.md deleted file mode 100644 index 64ac3486a3bf..000000000000 --- a/third_party/rust/uniffi_checksum_derive/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# UniFFI - a multi-language bindings generator for Rust - -UniFFI is a toolkit for building cross-platform software components in Rust. - -For the impatient, see [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/) -or [**the UniFFI examples**](https://github.com/mozilla/uniffi-rs/tree/main/examples#example-uniffi-components). - -By writing your core business logic in Rust and describing its interface in an "object model", -you can use UniFFI to help you: - -* Compile your Rust code into a shared library for use on different target platforms. -* Generate bindings to load and use the library from different target languages. - -You can describe your object model in an [interface definition file](https://mozilla.github.io/uniffi-rs/udl_file_spec.html) -or [by using proc-macros](https://mozilla.github.io/uniffi-rs/proc_macro/index.html). - -UniFFI is currently used extensively by Mozilla in Firefox mobile and desktop browsers; -written once in Rust, auto-generated bindings allow that functionality to be called -from both Kotlin (for Android apps) and Swift (for iOS apps). -It also has a growing community of users shipping various cool things to many users. - -UniFFI comes with support for **Kotlin**, **Swift**, **Python** and **Ruby** with 3rd party bindings available for **C#** and **Golang**. -Additional foreign language bindings can be developed externally and we welcome contributions to list them here. -See [Third-party foreign language bindings](#third-party-foreign-language-bindings). - -## User Guide - -You can read more about using the tool in [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/). - -We consider it ready for production use, but UniFFI is a long way from a 1.0 release with lots of internal work still going on. -We try hard to avoid breaking simple consumers, but more advanced things might break as you upgrade over time. - -### Etymology and Pronunciation - -ˈjuːnɪfaɪ. Pronounced to rhyme with "unify". - -A portmanteau word that also puns with "unify", to signify the joining of one codebase accessed from many languages. - -uni - [Latin ūni-, from ūnus, one] -FFI - [Abbreviation, Foreign Function Interface] - -## Alternative tools - -Other tools we know of which try and solve a similarly shaped problem are: - -* [Diplomat](https://github.com/rust-diplomat/diplomat/) - see our [writeup of - the different approach taken by that tool](docs/diplomat-and-macros.md) -* [Interoptopus](https://github.com/ralfbiedert/interoptopus/) - -(Please open a PR if you think other tools should be listed!) - -## Third-party foreign language bindings - -* [Kotlin Multiplatform support](https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings). The repository contains Kotlin Multiplatform bindings generation for UniFFI, letting you target both JVM and Native. -* [Go bindings](https://github.com/NordSecurity/uniffi-bindgen-go) -* [C# bindings](https://github.com/NordSecurity/uniffi-bindgen-cs) -* [Dart bindings](https://github.com/NiallBunting/uniffi-rs-dart) - -### External resources - -There are a few third-party resources that make it easier to work with UniFFI: - -* [Plugin support for `.udl` files](https://github.com/Lonami/uniffi-dl) for the IDEA platform ([*uniffi-dl* in the JetBrains marketplace](https://plugins.jetbrains.com/plugin/20527-uniffi-dl)). It provides syntax highlighting, code folding, code completion, reference resolution and navigation (among others features) for the [UniFFI Definition Language (UDL)](https://mozilla.github.io/uniffi-rs/). -* [cargo swift](https://github.com/antoniusnaumann/cargo-swift), a cargo plugin to build a Swift Package from Rust code. It provides an init command for setting up a UniFFI crate and a package command for building a Swift package from Rust code - without the need for additional configuration or build scripts. -* [Cargo NDK Gradle Plugin](https://github.com/willir/cargo-ndk-android-gradle) allows you to build Rust code using [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk), which generally makes Android library builds less painful. -* [`uniffi-starter`](https://github.com/ianthetechie/uniffi-starter) is a minimal project demonstrates a wide range of UniFFI in a complete project in a compact manner. It includes a full Android library build process, an XCFramework generation script, and example Swift package structure. - -(Please open a PR if you think other resources should be listed!) - -## Contributing - -If this tool sounds interesting to you, please help us develop it! You can: - -* View the [contributor guidelines](./docs/contributing.md). -* File or work on [issues](https://github.com/mozilla/uniffi-rs/issues) here in GitHub. -* Join discussions in the [#uniffi:mozilla.org](https://matrix.to/#/#uniffi:mozilla.org) - room on Matrix. - -## Code of Conduct - -This project is governed by Mozilla's [Community Participation Guidelines](./CODE_OF_CONDUCT.md). diff --git a/third_party/rust/uniffi_core/.cargo-checksum.json b/third_party/rust/uniffi_core/.cargo-checksum.json dissimilarity index 100% index 573f7a72c939..59804f7c89cc 100644 --- a/third_party/rust/uniffi_core/.cargo-checksum.json +++ b/third_party/rust/uniffi_core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c8969fbc6e8f6694e260ab78c94f9b4195d61afb7836b4c130b542d3b91b9200","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","release.toml":"b150796411fc6ff90b481218cb50f8ac7c07f5845aebdb8e17877d47e55b05b9","src/ffi/callbackinterface.rs":"f0184cf76bd86abb2815d260a87f85bd7060f5373ac6ef6f71955ece2a5075af","src/ffi/ffidefault.rs":"0db83fbcbc274c4c0daf7fb27833400568839b77a3496155840734c511d801e0","src/ffi/foreignbytes.rs":"d2b46e1a6317aa64801b855e0d12af6bcdef118d8036603d11c3cdaf6f35fdfe","src/ffi/foreigncallbacks.rs":"2b820a34b78705f5debc302a25c64d515a4aa7b3bdade083f4c1cfa2803664ae","src/ffi/foreignfuture.rs":"c1d621e41ea6af0c1d3959b46af8567c3fdc4164e7a82d635fcbb1da2c0737ac","src/ffi/handle.rs":"91f91469a81cb19edebb8bba433df62658cc66f6b54d5dc8520eb5793a85abd9","src/ffi/mod.rs":"30eea545299747838bf11b0698cfb71cedd3ca04d8cfb703c53198fcc44045c1","src/ffi/rustbuffer.rs":"0e725347f916834b17156413f406d5ca6c064b2cbc7437b051fe6692ad72c2aa","src/ffi/rustcalls.rs":"51c6499871c7d5eb4f80cabc806f26dd1df3b1090a2419d0d967aa9c5299a0a6","src/ffi/rustfuture/future.rs":"426cd0ad3c8cf008a7052a7d89856b6c6d5053b94e24325f5666d0281a40ec7f","src/ffi/rustfuture/mod.rs":"44568267e591f5b37f77acfdd6e60ae55ce48ab0a17fd81af3aeb31baa3d53e6","src/ffi/rustfuture/scheduler.rs":"c6484fff14c04596df5f306f2090366435dcff92561d317fde1ea9c097a9576b","src/ffi/rustfuture/tests.rs":"211241fb484a3a103eb0418e7d295850ea021bcd583fa1488f5efc68f33d5ab8","src/ffi_converter_impls.rs":"397c813f2e765462d7a7be524e6ac75e813a91a8ffd11c7e7df05f853213f77b","src/ffi_converter_traits.rs":"24c8cf6ada9b2f63b265e62c0f9092d640e533d0d7234e9156f92c3d1902f430","src/lib.rs":"1f6a031bbb160dfe46455a8bc24596f63b1e478f45579bfff62a62f58900bee4","src/metadata.rs":"83e463c377c0f501e58ac4eb5cc47c433c1473cecd47305fa89283e736b48d96","src/panichook.rs":"9f49c7994a8e5489c1105c488bb3f8c5571bc5f813e7be90441eca15da5c9851"},"package":"0ea3eb5474d50fc149b7e4d86b9c5bd4a61dcc167f0683902bf18ae7bbb3deef"} \ No newline at end of file +{"files":{"Cargo.toml":"b074f0db902264714faf879e99bdbc07df1550d75694f96751b499f98fecd16d","release.toml":"b150796411fc6ff90b481218cb50f8ac7c07f5845aebdb8e17877d47e55b05b9","src/ffi/callbackinterface.rs":"9e8650f0df087bf5e030a13d28f4990079e53613e656789b4b539d937a7fd288","src/ffi/ffidefault.rs":"f1ce099b92adbb12b160d513bae93342c7b6d806d7f6ebb665067db10af9a681","src/ffi/foreignbytes.rs":"d2b46e1a6317aa64801b855e0d12af6bcdef118d8036603d11c3cdaf6f35fdfe","src/ffi/foreigncallbacks.rs":"af8129a69ef23b92859e1cca0d666c95f0ed2c1fb2797f4495d824b65f774d03","src/ffi/foreignexecutor.rs":"123687921ce6dfb7f5bfa0736a630cfeff7f376b776ea03fc651da21ffd1cab8","src/ffi/mod.rs":"8117b08bbb7af3e97f66ed69c9690b60e8da0d6d8940349c7b9659a47cd8c92f","src/ffi/rustbuffer.rs":"8cc1f94b9ecba52b911da6a68155921c1b7f51b899d9874ddbc281a379941473","src/ffi/rustcalls.rs":"7caaa35ba8898c4b4983f07cefa80584ba00e753a11d496e578c80abe0cabe8b","src/ffi/rustfuture.rs":"d240426c8c8b83e3f6a2c0013e905298611287b2bb2022eb8161532209c635ca","src/ffi_converter_impls.rs":"82c1b47e02718610f2a5556997cd29ba5d8daf149d6353f470be0d9b971d968a","src/ffi_converter_traits.rs":"646c0d4aeb807d3e40db4d289f909030d0b2684087871a7d40d337680096b7d6","src/lib.rs":"4ad1a2899944a20e80a55d1c7bd01ff28395ace743a083c65847e6ea216fc5c8","src/metadata.rs":"6520ffcf2568a0d95f0f854acb6fc8aeaae26ef1f23fc576c2c50db72aa30eee","src/panichook.rs":"9f49c7994a8e5489c1105c488bb3f8c5571bc5f813e7be90441eca15da5c9851"},"package":"6121a127a3af1665cd90d12dd2b3683c2643c5103281d0fed5838324ca1fad5b"} \ No newline at end of file diff --git a/third_party/rust/uniffi_core/Cargo.toml b/third_party/rust/uniffi_core/Cargo.toml index ce36a2168a49..4d4cbe27581e 100644 --- a/third_party/rust/uniffi_core/Cargo.toml +++ b/third_party/rust/uniffi_core/Cargo.toml @@ -12,12 +12,11 @@ [package] edition = "2021" name = "uniffi_core" -version = "0.27.1" +version = "0.25.3" authors = ["Firefox Sync Team "] description = "a multi-language bindings generator for rust (runtime support code)" homepage = "https://mozilla.github.io/uniffi-rs" documentation = "https://mozilla.github.io/uniffi-rs" -readme = "README.md" keywords = [ "ffi", "bindgen", @@ -45,7 +44,7 @@ version = "0.4" version = "1.10.0" [dependencies.oneshot] -version = "0.1.6" +version = "0.1.5" features = ["async"] package = "oneshot-uniffi" @@ -57,4 +56,5 @@ version = "1.1.0" [features] default = [] +extern-rustbuffer = [] tokio = ["dep:async-compat"] diff --git a/third_party/rust/uniffi_core/README.md b/third_party/rust/uniffi_core/README.md deleted file mode 100644 index 64ac3486a3bf..000000000000 --- a/third_party/rust/uniffi_core/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# UniFFI - a multi-language bindings generator for Rust - -UniFFI is a toolkit for building cross-platform software components in Rust. - -For the impatient, see [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/) -or [**the UniFFI examples**](https://github.com/mozilla/uniffi-rs/tree/main/examples#example-uniffi-components). - -By writing your core business logic in Rust and describing its interface in an "object model", -you can use UniFFI to help you: - -* Compile your Rust code into a shared library for use on different target platforms. -* Generate bindings to load and use the library from different target languages. - -You can describe your object model in an [interface definition file](https://mozilla.github.io/uniffi-rs/udl_file_spec.html) -or [by using proc-macros](https://mozilla.github.io/uniffi-rs/proc_macro/index.html). - -UniFFI is currently used extensively by Mozilla in Firefox mobile and desktop browsers; -written once in Rust, auto-generated bindings allow that functionality to be called -from both Kotlin (for Android apps) and Swift (for iOS apps). -It also has a growing community of users shipping various cool things to many users. - -UniFFI comes with support for **Kotlin**, **Swift**, **Python** and **Ruby** with 3rd party bindings available for **C#** and **Golang**. -Additional foreign language bindings can be developed externally and we welcome contributions to list them here. -See [Third-party foreign language bindings](#third-party-foreign-language-bindings). - -## User Guide - -You can read more about using the tool in [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/). - -We consider it ready for production use, but UniFFI is a long way from a 1.0 release with lots of internal work still going on. -We try hard to avoid breaking simple consumers, but more advanced things might break as you upgrade over time. - -### Etymology and Pronunciation - -ˈjuːnɪfaɪ. Pronounced to rhyme with "unify". - -A portmanteau word that also puns with "unify", to signify the joining of one codebase accessed from many languages. - -uni - [Latin ūni-, from ūnus, one] -FFI - [Abbreviation, Foreign Function Interface] - -## Alternative tools - -Other tools we know of which try and solve a similarly shaped problem are: - -* [Diplomat](https://github.com/rust-diplomat/diplomat/) - see our [writeup of - the different approach taken by that tool](docs/diplomat-and-macros.md) -* [Interoptopus](https://github.com/ralfbiedert/interoptopus/) - -(Please open a PR if you think other tools should be listed!) - -## Third-party foreign language bindings - -* [Kotlin Multiplatform support](https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings). The repository contains Kotlin Multiplatform bindings generation for UniFFI, letting you target both JVM and Native. -* [Go bindings](https://github.com/NordSecurity/uniffi-bindgen-go) -* [C# bindings](https://github.com/NordSecurity/uniffi-bindgen-cs) -* [Dart bindings](https://github.com/NiallBunting/uniffi-rs-dart) - -### External resources - -There are a few third-party resources that make it easier to work with UniFFI: - -* [Plugin support for `.udl` files](https://github.com/Lonami/uniffi-dl) for the IDEA platform ([*uniffi-dl* in the JetBrains marketplace](https://plugins.jetbrains.com/plugin/20527-uniffi-dl)). It provides syntax highlighting, code folding, code completion, reference resolution and navigation (among others features) for the [UniFFI Definition Language (UDL)](https://mozilla.github.io/uniffi-rs/). -* [cargo swift](https://github.com/antoniusnaumann/cargo-swift), a cargo plugin to build a Swift Package from Rust code. It provides an init command for setting up a UniFFI crate and a package command for building a Swift package from Rust code - without the need for additional configuration or build scripts. -* [Cargo NDK Gradle Plugin](https://github.com/willir/cargo-ndk-android-gradle) allows you to build Rust code using [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk), which generally makes Android library builds less painful. -* [`uniffi-starter`](https://github.com/ianthetechie/uniffi-starter) is a minimal project demonstrates a wide range of UniFFI in a complete project in a compact manner. It includes a full Android library build process, an XCFramework generation script, and example Swift package structure. - -(Please open a PR if you think other resources should be listed!) - -## Contributing - -If this tool sounds interesting to you, please help us develop it! You can: - -* View the [contributor guidelines](./docs/contributing.md). -* File or work on [issues](https://github.com/mozilla/uniffi-rs/issues) here in GitHub. -* Join discussions in the [#uniffi:mozilla.org](https://matrix.to/#/#uniffi:mozilla.org) - room on Matrix. - -## Code of Conduct - -This project is governed by Mozilla's [Community Participation Guidelines](./CODE_OF_CONDUCT.md). diff --git a/third_party/rust/uniffi_core/src/ffi/callbackinterface.rs b/third_party/rust/uniffi_core/src/ffi/callbackinterface.rs index e7a4faab64b0..7be66880bb82 100644 --- a/third_party/rust/uniffi_core/src/ffi/callbackinterface.rs +++ b/third_party/rust/uniffi_core/src/ffi/callbackinterface.rs @@ -91,20 +91,121 @@ //! //! Uniffi generates a protocol or interface in client code in the foreign language must implement. //! -//! For each callback interface, UniFFI defines a VTable. -//! This is a `repr(C)` struct where each field is a `repr(C)` callback function pointer. -//! There is one field for each method, plus an extra field for the `uniffi_free` method. -//! The foreign code registers one VTable per callback interface with Rust. +//! For each callback interface, a `CallbackInternals` (on the Foreign Language side) and `ForeignCallbackInternals` +//! (on Rust side) manages the process through a `ForeignCallback`. There is one `ForeignCallback` per callback interface. //! -//! VTable methods have a similar signature to Rust scaffolding functions. -//! The one difference is that values are returned via an out pointer to work around a Python bug (https://bugs.python.org/issue5710). +//! Passing a callback interface implementation from foreign language (e.g. `AndroidKeychain`) into Rust causes the +//! `KeychainCallbackInternals` to store the instance in a handlemap. +//! +//! The object handle is passed over to Rust, and used to instantiate a struct `KeychainProxy` which implements +//! the trait. This proxy implementation is generate by Uniffi. The `KeychainProxy` object is then passed to +//! client code as `Box`. +//! +//! Methods on `KeychainProxy` objects (e.g. `self.keychain.get("username".into())`) encode the arguments into a `RustBuffer`. +//! Using the `ForeignCallback`, it calls the `CallbackInternals` object on the foreign language side using the +//! object handle, and the method selector. +//! +//! The `CallbackInternals` object unpacks the arguments from the passed buffer, gets the object out from the handlemap, +//! and calls the actual implementation of the method. +//! +//! If there's a return value, it is packed up in to another `RustBuffer` and used as the return value for +//! `ForeignCallback`. The caller of `ForeignCallback`, the `KeychainProxy` unpacks the returned buffer into the correct +//! type and then returns to client code. //! -//! The foreign object that implements the interface is represented by an opaque handle. -//! UniFFI generates a struct that implements the trait by calling VTable methods, passing the handle as the first parameter. -//! When the struct is dropped, the `uniffi_free` method is called. +use crate::{ForeignCallback, ForeignCallbackCell, Lift, LiftReturn, RustBuffer}; use std::fmt; +/// The method index used by the Drop trait to communicate to the foreign language side that Rust has finished with it, +/// and it can be deleted from the handle map. +pub const IDX_CALLBACK_FREE: u32 = 0; + +/// Result of a foreign callback invocation +#[repr(i32)] +#[derive(Debug, PartialEq, Eq)] +pub enum CallbackResult { + /// Successful call. + /// The return value is serialized to `buf_ptr`. + Success = 0, + /// Expected error. + /// This is returned when a foreign method throws an exception that corresponds to the Rust Err half of a Result. + /// The error value is serialized to `buf_ptr`. + Error = 1, + /// Unexpected error. + /// An error message string is serialized to `buf_ptr`. + UnexpectedError = 2, +} + +impl TryFrom for CallbackResult { + // On errors we return the unconverted value + type Error = i32; + + fn try_from(value: i32) -> Result { + match value { + 0 => Ok(Self::Success), + 1 => Ok(Self::Error), + 2 => Ok(Self::UnexpectedError), + n => Err(n), + } + } +} + +/// Struct to hold a foreign callback. +pub struct ForeignCallbackInternals { + callback_cell: ForeignCallbackCell, +} + +impl ForeignCallbackInternals { + pub const fn new() -> Self { + ForeignCallbackInternals { + callback_cell: ForeignCallbackCell::new(), + } + } + + pub fn set_callback(&self, callback: ForeignCallback) { + self.callback_cell.set(callback); + } + + /// Invoke a callback interface method on the foreign side and return the result + pub fn invoke_callback(&self, handle: u64, method: u32, args: RustBuffer) -> R + where + R: LiftReturn, + { + let mut ret_rbuf = RustBuffer::new(); + let callback = self.callback_cell.get(); + let raw_result = unsafe { + callback( + handle, + method, + args.data_pointer(), + args.len() as i32, + &mut ret_rbuf, + ) + }; + let result = CallbackResult::try_from(raw_result) + .unwrap_or_else(|code| panic!("Callback failed with unexpected return code: {code}")); + match result { + CallbackResult::Success => R::lift_callback_return(ret_rbuf), + CallbackResult::Error => R::lift_callback_error(ret_rbuf), + CallbackResult::UnexpectedError => { + let reason = if !ret_rbuf.is_empty() { + match >::try_lift(ret_rbuf) { + Ok(s) => s, + Err(e) => { + log::error!("{{ trait_name }} Error reading ret_buf: {e}"); + String::from("[Error reading reason]") + } + } + } else { + RustBuffer::destroy(ret_rbuf); + String::from("[Unknown Reason]") + }; + R::handle_callback_unexpected_error(UnexpectedUniFFICallbackError { reason }) + } + } + } +} + /// Used when internal/unexpected error happened when calling a foreign callback, for example when /// a unknown exception is raised /// @@ -115,10 +216,8 @@ pub struct UnexpectedUniFFICallbackError { } impl UnexpectedUniFFICallbackError { - pub fn new(reason: impl fmt::Display) -> Self { - Self { - reason: reason.to_string(), - } + pub fn from_reason(reason: String) -> Self { + Self { reason } } } diff --git a/third_party/rust/uniffi_core/src/ffi/ffidefault.rs b/third_party/rust/uniffi_core/src/ffi/ffidefault.rs index a992ab73843b..1f86f6b13b3d 100644 --- a/third_party/rust/uniffi_core/src/ffi/ffidefault.rs +++ b/third_party/rust/uniffi_core/src/ffi/ffidefault.rs @@ -39,12 +39,6 @@ impl FfiDefault for () { fn ffi_default() {} } -impl FfiDefault for crate::Handle { - fn ffi_default() -> Self { - Self::default() - } -} - impl FfiDefault for *const std::ffi::c_void { fn ffi_default() -> Self { std::ptr::null() @@ -57,10 +51,9 @@ impl FfiDefault for crate::RustBuffer { } } -impl FfiDefault for crate::ForeignFuture { +impl FfiDefault for crate::ForeignExecutorHandle { fn ffi_default() -> Self { - extern "C" fn free(_handle: u64) {} - crate::ForeignFuture { handle: 0, free } + Self(std::ptr::null()) } } diff --git a/third_party/rust/uniffi_core/src/ffi/foreigncallbacks.rs b/third_party/rust/uniffi_core/src/ffi/foreigncallbacks.rs index 326ff127473b..ac2463cd8ed5 100644 --- a/third_party/rust/uniffi_core/src/ffi/foreigncallbacks.rs +++ b/third_party/rust/uniffi_core/src/ffi/foreigncallbacks.rs @@ -8,32 +8,96 @@ //! code loads the exported library. For each callback type, we also define a "cell" type for //! storing the callback. -use std::{ - ptr::{null_mut, NonNull}, - sync::atomic::{AtomicPtr, Ordering}, -}; - -// Cell type that stores any NonNull -#[doc(hidden)] -pub struct UniffiForeignPointerCell(AtomicPtr); - -impl UniffiForeignPointerCell { - pub const fn new() -> Self { - Self(AtomicPtr::new(null_mut())) - } - - pub fn set(&self, callback: NonNull) { - self.0.store(callback.as_ptr(), Ordering::Relaxed); - } - - pub fn get(&self) -> &T { - unsafe { - NonNull::new(self.0.load(Ordering::Relaxed)) - .expect("Foreign pointer not set. This is likely a uniffi bug.") - .as_mut() +use std::sync::atomic::{AtomicUsize, Ordering}; + +use crate::{ForeignExecutorHandle, RustBuffer, RustTaskCallback}; + +/// ForeignCallback is the Rust representation of a foreign language function. +/// It is the basis for all callbacks interfaces. It is registered exactly once per callback interface, +/// at library start up time. +/// Calling this method is only done by generated objects which mirror callback interfaces objects in the foreign language. +/// +/// * The `handle` is the key into a handle map on the other side of the FFI used to look up the foreign language object +/// that implements the callback interface/trait. +/// * The `method` selector specifies the method that will be called on the object, by looking it up in a list of methods from +/// the IDL. The list is 1 indexed. Note that the list of methods is generated by UniFFI from the IDL and used in all +/// bindings, so we can rely on the method list being stable within the same run of UniFFI. +/// * `args_data` and `args_len` represents a serialized buffer of arguments to the function. The scaffolding code +/// writes the callback arguments to this buffer, in order, using `FfiConverter.write()`. The bindings code reads the +/// arguments from the buffer and passes them to the user's callback. +/// * `buf_ptr` is a pointer to where the resulting buffer will be written. UniFFI will allocate a +/// buffer to write the result into. +/// * Callbacks return one of the `CallbackResult` values +/// Note: The output buffer might still contain 0 bytes of data. +pub type ForeignCallback = unsafe extern "C" fn( + handle: u64, + method: u32, + args_data: *const u8, + args_len: i32, + buf_ptr: *mut RustBuffer, +) -> i32; + +/// Callback to schedule a Rust call with a `ForeignExecutor`. The bindings code registers exactly +/// one of these with the Rust code. +/// +/// Delay is an approximate amount of ms to wait before scheduling the call. Delay is usually 0, +/// which means schedule sometime soon. +/// +/// As a special case, when Rust drops the foreign executor, with `task=null`. The foreign +/// bindings should release the reference to the executor that was reserved for Rust. +/// +/// This callback can be invoked from any thread, including threads created by Rust. +/// +/// The callback should return one of the `ForeignExecutorCallbackResult` values. +pub type ForeignExecutorCallback = extern "C" fn( + executor: ForeignExecutorHandle, + delay: u32, + task: Option, + task_data: *const (), +) -> i8; + +/// Store a [ForeignCallback] pointer +pub(crate) struct ForeignCallbackCell(AtomicUsize); + +/// Store a [ForeignExecutorCallback] pointer +pub(crate) struct ForeignExecutorCallbackCell(AtomicUsize); + +/// Macro to define foreign callback types as well as the callback cell. +macro_rules! impl_foreign_callback_cell { + ($callback_type:ident, $cell_type:ident) => { + // Overly-paranoid sanity checking to ensure that these types are + // convertible between each-other. `transmute` actually should check this for + // us too, but this helps document the invariants we rely on in this code. + // + // Note that these are guaranteed by + // https://rust-lang.github.io/unsafe-code-guidelines/layout/function-pointers.html + // and thus this is a little paranoid. + static_assertions::assert_eq_size!(usize, $callback_type); + static_assertions::assert_eq_size!(usize, Option<$callback_type>); + + impl $cell_type { + pub const fn new() -> Self { + Self(AtomicUsize::new(0)) + } + + pub fn set(&self, callback: $callback_type) { + // Store the pointer using Ordering::Relaxed. This is sufficient since callback + // should be set at startup, before there's any chance of using them. + self.0.store(callback as usize, Ordering::Relaxed); + } + + pub fn get(&self) -> $callback_type { + let ptr_value = self.0.load(Ordering::Relaxed); + unsafe { + // SAFETY: self.0 was set in `set` from our function pointer type, so + // it's safe to transmute it back here. + ::std::mem::transmute::>(ptr_value) + .expect("Bug: callback not set. This is likely a uniffi bug.") + } + } } - } + }; } -unsafe impl Send for UniffiForeignPointerCell {} -unsafe impl Sync for UniffiForeignPointerCell {} +impl_foreign_callback_cell!(ForeignCallback, ForeignCallbackCell); +impl_foreign_callback_cell!(ForeignExecutorCallback, ForeignExecutorCallbackCell); diff --git a/third_party/rust/uniffi_core/src/ffi/foreignexecutor.rs b/third_party/rust/uniffi_core/src/ffi/foreignexecutor.rs new file mode 100644 index 000000000000..7b1cb9bd802c --- /dev/null +++ b/third_party/rust/uniffi_core/src/ffi/foreignexecutor.rs @@ -0,0 +1,487 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Schedule tasks using a foreign executor. + +use std::panic; + +use crate::{ForeignExecutorCallback, ForeignExecutorCallbackCell}; + +/// Opaque handle for a foreign task executor. +/// +/// Foreign code can either use an actual pointer, or use an integer value casted to it. +#[repr(transparent)] +#[derive(Clone, Copy, Debug)] +pub struct ForeignExecutorHandle(pub(crate) *const ()); + +// Implement Send + Sync for `ForeignExecutor`. The foreign bindings code is responsible for +// making the `ForeignExecutorCallback` thread-safe. +unsafe impl Send for ForeignExecutorHandle {} + +unsafe impl Sync for ForeignExecutorHandle {} + +/// Result code returned by `ForeignExecutorCallback` +#[repr(i8)] +#[derive(Debug, PartialEq, Eq)] +pub enum ForeignExecutorCallbackResult { + /// Callback was scheduled successfully + Success = 0, + /// Callback couldn't be scheduled because the foreign executor is canceled/closed. + Cancelled = 1, + /// Callback couldn't be scheduled because of some other error + Error = 2, +} + +impl ForeignExecutorCallbackResult { + /// Check the result code for the foreign executor callback + /// + /// If the result was `ForeignExecutorCallbackResult.Success`, this method returns `true`. + /// + /// If not, this method returns `false`, logging errors for any unexpected return values + pub fn check_result_code(result: i8) -> bool { + match result { + n if n == ForeignExecutorCallbackResult::Success as i8 => true, + n if n == ForeignExecutorCallbackResult::Cancelled as i8 => false, + n if n == ForeignExecutorCallbackResult::Error as i8 => { + log::error!( + "ForeignExecutorCallbackResult::Error returned by foreign executor callback" + ); + false + } + n => { + log::error!("Unknown code ({n}) returned by foreign executor callback"); + false + } + } + } +} + +// Option should use the null pointer optimization and be represented in C as a +// regular pointer. Let's check that. +static_assertions::assert_eq_size!(usize, Option); + +/// Callback for a Rust task, this is what the foreign executor invokes +/// +/// The task will be passed the `task_data` passed to `ForeignExecutorCallback` in addition to one +/// of the `RustTaskCallbackCode` values. +pub type RustTaskCallback = extern "C" fn(*const (), RustTaskCallbackCode); + +/// Passed to a `RustTaskCallback` function when the executor invokes them. +/// +/// Every `RustTaskCallback` will be invoked eventually, this code is used to distinguish the times +/// when it's invoked successfully vs times when the callback is being called because the foreign +/// executor has been cancelled / shutdown +#[repr(i8)] +#[derive(Debug, PartialEq, Eq)] +pub enum RustTaskCallbackCode { + /// Successful task callback invocation + Success = 0, + /// The `ForeignExecutor` has been cancelled. + /// + /// This signals that any progress using the executor should be halted. In particular, Futures + /// should not continue to progress. + Cancelled = 1, +} + +static FOREIGN_EXECUTOR_CALLBACK: ForeignExecutorCallbackCell = ForeignExecutorCallbackCell::new(); + +/// Set the global ForeignExecutorCallback. This is called by the foreign bindings, normally +/// during initialization. +pub fn foreign_executor_callback_set(callback: ForeignExecutorCallback) { + FOREIGN_EXECUTOR_CALLBACK.set(callback); +} + +/// Schedule Rust calls using a foreign executor +#[derive(Debug)] +pub struct ForeignExecutor { + pub(crate) handle: ForeignExecutorHandle, +} + +impl ForeignExecutor { + pub fn new(executor: ForeignExecutorHandle) -> Self { + Self { handle: executor } + } + + /// Schedule a closure to be run. + /// + /// This method can be used for "fire-and-forget" style calls, where the calling code doesn't + /// need to await the result. + /// + /// Closure requirements: + /// - Send: since the closure will likely run on a different thread + /// - 'static: since it runs at an arbitrary time, so all references need to be 'static + /// - panic::UnwindSafe: if the closure panics, it should not corrupt any data + pub fn schedule(&self, delay: u32, task: F) { + let leaked_ptr: *mut F = Box::leak(Box::new(task)); + if !schedule_raw( + self.handle, + delay, + schedule_callback::, + leaked_ptr as *const (), + ) { + // If schedule_raw() failed, drop the leaked box since `schedule_callback()` has not been + // scheduled to run. + unsafe { + drop(Box::::from_raw(leaked_ptr)); + }; + } + } + + /// Schedule a closure to be run and get a Future for the result + /// + /// Closure requirements: + /// - Send: since the closure will likely run on a different thread + /// - 'static: since it runs at an arbitrary time, so all references need to be 'static + /// - panic::UnwindSafe: if the closure panics, it should not corrupt any data + pub async fn run(&self, delay: u32, closure: F) -> T + where + F: FnOnce() -> T + Send + 'static + panic::UnwindSafe, + T: Send + 'static, + { + // Create a oneshot channel to handle the future + let (sender, receiver) = oneshot::channel(); + // We can use `AssertUnwindSafe` here because: + // - The closure is unwind safe + // - `Sender` is not marked unwind safe, maybe this is just an oversight in the oneshot + // library. However, calling `send()` and dropping the Sender should certainly be + // unwind safe. `send()` should probably not panic at all and if it does it shouldn't + // do it in a way that breaks the Receiver. + // - Calling `expect` may result in a panic, but this should should not break either the + // Sender or Receiver. + self.schedule( + delay, + panic::AssertUnwindSafe(move || { + sender.send(closure()).expect("Error sending future result") + }), + ); + receiver.await.expect("Error receiving future result") + } +} + +/// Low-level schedule interface +/// +/// When using this function, take care to ensure that the `ForeignExecutor` that holds the +/// `ForeignExecutorHandle` has not been dropped. +/// +/// Returns true if the callback was successfully scheduled +pub(crate) fn schedule_raw( + handle: ForeignExecutorHandle, + delay: u32, + callback: RustTaskCallback, + data: *const (), +) -> bool { + let result_code = (FOREIGN_EXECUTOR_CALLBACK.get())(handle, delay, Some(callback), data); + ForeignExecutorCallbackResult::check_result_code(result_code) +} + +impl Drop for ForeignExecutor { + fn drop(&mut self) { + (FOREIGN_EXECUTOR_CALLBACK.get())(self.handle, 0, None, std::ptr::null()); + } +} + +extern "C" fn schedule_callback(data: *const (), status_code: RustTaskCallbackCode) +where + F: FnOnce() + Send + 'static + panic::UnwindSafe, +{ + // No matter what, we need to call Box::from_raw() to balance the Box::leak() call. + let task = unsafe { Box::from_raw(data as *mut F) }; + // Skip running the task for the `RustTaskCallbackCode::Cancelled` code + if status_code == RustTaskCallbackCode::Success { + run_task(task); + } +} + +/// Run a scheduled task, catching any panics. +/// +/// If there are panics, then we will log a warning and return None. +fn run_task T + panic::UnwindSafe, T>(task: F) -> Option { + match panic::catch_unwind(task) { + Ok(v) => Some(v), + Err(cause) => { + let message = if let Some(s) = cause.downcast_ref::<&'static str>() { + (*s).to_string() + } else if let Some(s) = cause.downcast_ref::() { + s.clone() + } else { + "Unknown panic!".to_string() + }; + log::warn!("Error calling UniFFI callback function: {message}"); + None + } + } +} + +#[cfg(test)] +pub use test::MockEventLoop; + +#[cfg(test)] +mod test { + use super::*; + use std::{ + future::Future, + pin::Pin, + sync::{ + atomic::{AtomicU32, Ordering}, + Arc, Mutex, Once, + }, + task::{Context, Poll, Wake, Waker}, + }; + + /// Simulate an event loop / task queue / coroutine scope on the foreign side + /// + /// This simply collects scheduled calls into a Vec for testing purposes. + /// + /// Most of the MockEventLoop methods are `pub` since it's also used by the `rustfuture` tests. + pub struct MockEventLoop { + // Wrap everything in a mutex since we typically share access to MockEventLoop via an Arc + inner: Mutex, + } + + pub struct MockEventLoopInner { + // calls that have been scheduled + calls: Vec<(u32, Option, *const ())>, + // has the event loop been shutdown? + is_shutdown: bool, + } + + unsafe impl Send for MockEventLoopInner {} + + static FOREIGN_EXECUTOR_CALLBACK_INIT: Once = Once::new(); + + impl MockEventLoop { + pub fn new() -> Arc { + // Make sure we install a foreign executor callback that can deal with mock event loops + FOREIGN_EXECUTOR_CALLBACK_INIT + .call_once(|| foreign_executor_callback_set(mock_executor_callback)); + + Arc::new(Self { + inner: Mutex::new(MockEventLoopInner { + calls: vec![], + is_shutdown: false, + }), + }) + } + + /// Create a new ForeignExecutorHandle + pub fn new_handle(self: &Arc) -> ForeignExecutorHandle { + // To keep the memory management simple, we simply leak an arc reference for this. We + // only create a handful of these in the tests so there's no need for proper cleanup. + ForeignExecutorHandle(Arc::into_raw(Arc::clone(self)) as *const ()) + } + + pub fn new_executor(self: &Arc) -> ForeignExecutor { + ForeignExecutor { + handle: self.new_handle(), + } + } + + /// Get the current number of scheduled calls + pub fn call_count(&self) -> usize { + self.inner.lock().unwrap().calls.len() + } + + /// Get the last scheduled call + pub fn last_call(&self) -> (u32, Option, *const ()) { + self.inner + .lock() + .unwrap() + .calls + .last() + .cloned() + .expect("no calls scheduled") + } + + /// Run all currently scheduled calls + pub fn run_all_calls(&self) { + let mut inner = self.inner.lock().unwrap(); + let is_shutdown = inner.is_shutdown; + for (_delay, callback, data) in inner.calls.drain(..) { + if !is_shutdown { + callback.unwrap()(data, RustTaskCallbackCode::Success); + } else { + callback.unwrap()(data, RustTaskCallbackCode::Cancelled); + } + } + } + + /// Shutdown the eventloop, causing scheduled calls and future calls to be cancelled + pub fn shutdown(&self) { + self.inner.lock().unwrap().is_shutdown = true; + } + } + + // `ForeignExecutorCallback` that we install for testing + extern "C" fn mock_executor_callback( + handle: ForeignExecutorHandle, + delay: u32, + task: Option, + task_data: *const (), + ) -> i8 { + let eventloop = handle.0 as *const MockEventLoop; + let mut inner = unsafe { (*eventloop).inner.lock().unwrap() }; + if inner.is_shutdown { + ForeignExecutorCallbackResult::Cancelled as i8 + } else { + inner.calls.push((delay, task, task_data)); + ForeignExecutorCallbackResult::Success as i8 + } + } + + #[test] + fn test_schedule_raw() { + extern "C" fn callback(data: *const (), _status_code: RustTaskCallbackCode) { + unsafe { + *(data as *mut u32) += 1; + } + } + + let eventloop = MockEventLoop::new(); + + let value: u32 = 0; + assert_eq!(eventloop.call_count(), 0); + + schedule_raw( + eventloop.new_handle(), + 0, + callback, + &value as *const u32 as *const (), + ); + assert_eq!(eventloop.call_count(), 1); + assert_eq!(value, 0); + + eventloop.run_all_calls(); + assert_eq!(eventloop.call_count(), 0); + assert_eq!(value, 1); + } + + #[test] + fn test_schedule() { + let eventloop = MockEventLoop::new(); + let executor = eventloop.new_executor(); + let value = Arc::new(AtomicU32::new(0)); + assert_eq!(eventloop.call_count(), 0); + + let value2 = value.clone(); + executor.schedule(0, move || { + value2.fetch_add(1, Ordering::Relaxed); + }); + assert_eq!(eventloop.call_count(), 1); + assert_eq!(value.load(Ordering::Relaxed), 0); + + eventloop.run_all_calls(); + assert_eq!(eventloop.call_count(), 0); + assert_eq!(value.load(Ordering::Relaxed), 1); + } + + #[derive(Default)] + struct MockWaker { + wake_count: AtomicU32, + } + + impl Wake for MockWaker { + fn wake(self: Arc) { + self.wake_count.fetch_add(1, Ordering::Relaxed); + } + } + + #[test] + fn test_run() { + let eventloop = MockEventLoop::new(); + let executor = eventloop.new_executor(); + let mock_waker = Arc::new(MockWaker::default()); + let waker = Waker::from(mock_waker.clone()); + let mut context = Context::from_waker(&waker); + assert_eq!(eventloop.call_count(), 0); + + let mut future = executor.run(0, move || "test-return-value"); + unsafe { + assert_eq!( + Pin::new_unchecked(&mut future).poll(&mut context), + Poll::Pending + ); + } + assert_eq!(eventloop.call_count(), 1); + assert_eq!(mock_waker.wake_count.load(Ordering::Relaxed), 0); + + eventloop.run_all_calls(); + assert_eq!(eventloop.call_count(), 0); + assert_eq!(mock_waker.wake_count.load(Ordering::Relaxed), 1); + unsafe { + assert_eq!( + Pin::new_unchecked(&mut future).poll(&mut context), + Poll::Ready("test-return-value") + ); + } + } + + #[test] + fn test_drop() { + let eventloop = MockEventLoop::new(); + let executor = eventloop.new_executor(); + + drop(executor); + // Calling drop should schedule a call with null task data. + assert_eq!(eventloop.call_count(), 1); + assert_eq!(eventloop.last_call().1, None); + } + + // Test that cancelled calls never run + #[test] + fn test_cancelled_call() { + let eventloop = MockEventLoop::new(); + let executor = eventloop.new_executor(); + // Create a shared counter + let counter = Arc::new(AtomicU32::new(0)); + // schedule increments using both `schedule()` and run()` + let counter_clone = Arc::clone(&counter); + executor.schedule(0, move || { + counter_clone.fetch_add(1, Ordering::Relaxed); + }); + let counter_clone = Arc::clone(&counter); + let future = executor.run(0, move || { + counter_clone.fetch_add(1, Ordering::Relaxed); + }); + // shutdown the eventloop before the scheduled call gets a chance to run. + eventloop.shutdown(); + // `run_all_calls()` will cause the scheduled task callbacks to run, but will pass + // `RustTaskCallbackCode::Cancelled` to it. This drop the scheduled closure without executing + // it. + eventloop.run_all_calls(); + + assert_eq!(counter.load(Ordering::Relaxed), 0); + drop(future); + } + + // Test that when scheduled calls are cancelled, the closures are dropped properly + #[test] + fn test_cancellation_drops_closures() { + let eventloop = MockEventLoop::new(); + let executor = eventloop.new_executor(); + + // Create an Arc<> that we will move into the closures to test if they are dropped or not + let arc = Arc::new(0); + let arc_clone = Arc::clone(&arc); + executor.schedule(0, move || assert_eq!(*arc_clone, 0)); + let arc_clone = Arc::clone(&arc); + let future = executor.run(0, move || assert_eq!(*arc_clone, 0)); + + // shutdown the eventloop and run the (cancelled) scheduled calls. + eventloop.shutdown(); + eventloop.run_all_calls(); + // try to schedule some more calls now that the loop has been shutdown + let arc_clone = Arc::clone(&arc); + executor.schedule(0, move || assert_eq!(*arc_clone, 0)); + let arc_clone = Arc::clone(&arc); + let future2 = executor.run(0, move || assert_eq!(*arc_clone, 0)); + + // Drop the futures so they don't hold on to any references + drop(future); + drop(future2); + + // All of these closures should have been dropped by now, there only remaining arc + // reference should be the original + assert_eq!(Arc::strong_count(&arc), 1); + } +} diff --git a/third_party/rust/uniffi_core/src/ffi/foreignfuture.rs b/third_party/rust/uniffi_core/src/ffi/foreignfuture.rs deleted file mode 100644 index be6a214e8417..000000000000 --- a/third_party/rust/uniffi_core/src/ffi/foreignfuture.rs +++ /dev/null @@ -1,241 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//! This module defines a Rust Future that wraps an async foreign function call. -//! -//! The general idea is to create a [oneshot::Channel], hand the sender to the foreign side, and -//! await the receiver side on the Rust side. -//! -//! The foreign side should: -//! * Input a [ForeignFutureCallback] and a `u64` handle in their scaffolding function. -//! This is the sender, converted to a raw pointer, and an extern "C" function that sends the result. -//! * Return a [ForeignFuture], which represents the foreign task object corresponding to the async function. -//! * Call the [ForeignFutureCallback] when the async function completes with: -//! * The `u64` handle initially passed in -//! * The `ForeignFutureResult` for the call -//! * Wait for the [ForeignFutureHandle::free] function to be called to free the task object. -//! If this is called before the task completes, then the task will be cancelled. - -use crate::{LiftReturn, RustCallStatus, UnexpectedUniFFICallbackError}; - -/// Handle for a foreign future -pub type ForeignFutureHandle = u64; - -/// Handle for a callback data associated with a foreign future. -pub type ForeignFutureCallbackData = *mut (); - -/// Callback that's passed to a foreign async functions. -/// -/// See `LiftReturn` trait for how this is implemented. -pub type ForeignFutureCallback = - extern "C" fn(oneshot_handle: u64, ForeignFutureResult); - -/// C struct that represents the result of a foreign future -#[repr(C)] -pub struct ForeignFutureResult { - // Note: for void returns, T is `()`, which isn't directly representable with C since it's a ZST. - // Foreign code should treat that case as if there was no `return_value` field. - return_value: T, - call_status: RustCallStatus, -} - -/// Perform a call to a foreign async method - -/// C struct that represents the foreign future. -/// -/// This is what's returned by the async scaffolding functions. -#[repr(C)] -pub struct ForeignFuture { - pub handle: ForeignFutureHandle, - pub free: extern "C" fn(handle: ForeignFutureHandle), -} - -impl Drop for ForeignFuture { - fn drop(&mut self) { - (self.free)(self.handle) - } -} - -unsafe impl Send for ForeignFuture {} - -pub async fn foreign_async_call(call_scaffolding_function: F) -> T -where - F: FnOnce(ForeignFutureCallback, u64) -> ForeignFuture, - T: LiftReturn, -{ - let (sender, receiver) = oneshot::channel::>(); - // Keep the ForeignFuture around, even though we don't ever use it. - // The important thing is that the ForeignFuture will be dropped when this Future is. - let _foreign_future = - call_scaffolding_function(foreign_future_complete::, sender.into_raw() as u64); - match receiver.await { - Ok(result) => T::lift_foreign_return(result.return_value, result.call_status), - Err(e) => { - // This shouldn't happen in practice, but we can do our best to recover - T::handle_callback_unexpected_error(UnexpectedUniFFICallbackError::new(format!( - "Error awaiting foreign future: {e}" - ))) - } - } -} - -pub extern "C" fn foreign_future_complete, UT>( - oneshot_handle: u64, - result: ForeignFutureResult, -) { - let channel = unsafe { oneshot::Sender::from_raw(oneshot_handle as *mut ()) }; - // Ignore errors in send. - // - // Error means the receiver was already dropped which will happen when the future is cancelled. - let _ = channel.send(result); -} - -#[cfg(test)] -mod test { - use super::*; - use crate::{Lower, RustBuffer}; - use once_cell::sync::OnceCell; - use std::{ - future::Future, - pin::Pin, - sync::{ - atomic::{AtomicU32, Ordering}, - Arc, - }, - task::{Context, Poll, Wake}, - }; - - struct MockForeignFuture { - freed: Arc, - callback_info: Arc, u64)>>, - rust_future: Option>>>, - } - - impl MockForeignFuture { - fn new() -> Self { - let callback_info = Arc::new(OnceCell::new()); - let freed = Arc::new(AtomicU32::new(0)); - - let rust_future: Pin>> = { - let callback_info = callback_info.clone(); - let freed = freed.clone(); - Box::pin(foreign_async_call::<_, String, crate::UniFfiTag>( - move |callback, data| { - callback_info.set((callback, data)).unwrap(); - ForeignFuture { - handle: Arc::into_raw(freed) as *mut () as u64, - free: Self::free, - } - }, - )) - }; - let rust_future = Some(rust_future); - let mut mock_foreign_future = Self { - freed, - callback_info, - rust_future, - }; - // Poll the future once, to start it up. This ensures that `callback_info` is set. - let _ = mock_foreign_future.poll(); - mock_foreign_future - } - - fn poll(&mut self) -> Poll { - let waker = Arc::new(NoopWaker).into(); - let mut context = Context::from_waker(&waker); - self.rust_future - .as_mut() - .unwrap() - .as_mut() - .poll(&mut context) - } - - fn complete_success(&self, value: String) { - let (callback, data) = self.callback_info.get().unwrap(); - callback( - *data, - ForeignFutureResult { - return_value: >::lower(value), - call_status: RustCallStatus::new(), - }, - ); - } - - fn complete_error(&self, error_message: String) { - let (callback, data) = self.callback_info.get().unwrap(); - callback( - *data, - ForeignFutureResult { - return_value: RustBuffer::default(), - call_status: RustCallStatus::error(error_message), - }, - ); - } - - fn drop_future(&mut self) { - self.rust_future = None - } - - fn free_count(&self) -> u32 { - self.freed.load(Ordering::Relaxed) - } - - extern "C" fn free(handle: u64) { - let flag = unsafe { Arc::from_raw(handle as *mut AtomicU32) }; - flag.fetch_add(1, Ordering::Relaxed); - } - } - - struct NoopWaker; - - impl Wake for NoopWaker { - fn wake(self: Arc) {} - } - - #[test] - fn test_foreign_future() { - let mut mock_foreign_future = MockForeignFuture::new(); - assert_eq!(mock_foreign_future.poll(), Poll::Pending); - mock_foreign_future.complete_success("It worked!".to_owned()); - assert_eq!( - mock_foreign_future.poll(), - Poll::Ready("It worked!".to_owned()) - ); - // Since the future is complete, it should free the foreign future - assert_eq!(mock_foreign_future.free_count(), 1); - } - - #[test] - #[should_panic] - fn test_foreign_future_error() { - let mut mock_foreign_future = MockForeignFuture::new(); - assert_eq!(mock_foreign_future.poll(), Poll::Pending); - mock_foreign_future.complete_error("It Failed!".to_owned()); - let _ = mock_foreign_future.poll(); - } - - #[test] - fn test_drop_after_complete() { - let mut mock_foreign_future = MockForeignFuture::new(); - mock_foreign_future.complete_success("It worked!".to_owned()); - assert_eq!(mock_foreign_future.free_count(), 0); - assert_eq!( - mock_foreign_future.poll(), - Poll::Ready("It worked!".to_owned()) - ); - // Dropping the future after it's complete should not panic, and not cause a double-free - mock_foreign_future.drop_future(); - assert_eq!(mock_foreign_future.free_count(), 1); - } - - #[test] - fn test_drop_before_complete() { - let mut mock_foreign_future = MockForeignFuture::new(); - mock_foreign_future.complete_success("It worked!".to_owned()); - // Dropping the future before it's complete should cancel the future - assert_eq!(mock_foreign_future.free_count(), 0); - mock_foreign_future.drop_future(); - assert_eq!(mock_foreign_future.free_count(), 1); - } -} diff --git a/third_party/rust/uniffi_core/src/ffi/handle.rs b/third_party/rust/uniffi_core/src/ffi/handle.rs deleted file mode 100644 index 8ee2f46c359d..000000000000 --- a/third_party/rust/uniffi_core/src/ffi/handle.rs +++ /dev/null @@ -1,46 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/// Object handle -/// -/// Handles opaque `u64` values used to pass objects across the FFI, both for objects implemented in -/// Rust and ones implemented in the foreign language. -/// -/// Rust handles are generated by leaking a raw pointer -/// Foreign handles are generated with a handle map that only generates odd values. -/// For all currently supported architectures and hopefully any ones we add in the future: -/// * 0 is an invalid value. -/// * The lowest bit will always be set for foreign handles and never set for Rust ones (since the -/// leaked pointer will be aligned). -/// -/// Rust handles are mainly managed is through the [crate::HandleAlloc] trait. -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)] -#[repr(transparent)] -pub struct Handle(u64); - -impl Handle { - pub fn from_pointer(ptr: *const T) -> Self { - Self(ptr as u64) - } - - pub fn as_pointer(&self) -> *const T { - self.0 as *const T - } - - pub fn from_raw(raw: u64) -> Option { - if raw == 0 { - None - } else { - Some(Self(raw)) - } - } - - pub fn from_raw_unchecked(raw: u64) -> Self { - Self(raw) - } - - pub fn as_raw(&self) -> u64 { - self.0 - } -} diff --git a/third_party/rust/uniffi_core/src/ffi/mod.rs b/third_party/rust/uniffi_core/src/ffi/mod.rs index acaf2b0d06fa..b60632329727 100644 --- a/third_party/rust/uniffi_core/src/ffi/mod.rs +++ b/third_party/rust/uniffi_core/src/ffi/mod.rs @@ -8,8 +8,7 @@ pub mod callbackinterface; pub mod ffidefault; pub mod foreignbytes; pub mod foreigncallbacks; -pub mod foreignfuture; -pub mod handle; +pub mod foreignexecutor; pub mod rustbuffer; pub mod rustcalls; pub mod rustfuture; @@ -18,8 +17,7 @@ pub use callbackinterface::*; pub use ffidefault::FfiDefault; pub use foreignbytes::*; pub use foreigncallbacks::*; -pub use foreignfuture::*; -pub use handle::*; +pub use foreignexecutor::*; pub use rustbuffer::*; pub use rustcalls::*; pub use rustfuture::*; diff --git a/third_party/rust/uniffi_core/src/ffi/rustbuffer.rs b/third_party/rust/uniffi_core/src/ffi/rustbuffer.rs index 8b2972968c68..e09e3be89a11 100644 --- a/third_party/rust/uniffi_core/src/ffi/rustbuffer.rs +++ b/third_party/rust/uniffi_core/src/ffi/rustbuffer.rs @@ -52,11 +52,11 @@ use crate::ffi::{rust_call, ForeignBytes, RustCallStatus}; #[derive(Debug)] pub struct RustBuffer { /// The allocated capacity of the underlying `Vec`. - /// In Rust this is a `usize`, but we use an `u64` to keep the foreign binding code simple. - capacity: u64, + /// In Rust this is a `usize`, but we use an `i32` for compatibility with JNA. + capacity: i32, /// The occupied length of the underlying `Vec`. - /// In Rust this is a `usize`, but we use an `u64` to keep the foreign binding code simple. - len: u64, + /// In Rust this is a `usize`, but we use an `i32` for compatibility with JNA. + len: i32, /// The pointer to the allocated buffer of the `Vec`. data: *mut u8, } @@ -84,7 +84,7 @@ impl RustBuffer { /// # Safety /// /// You must ensure that the raw parts uphold the documented invariants of this class. - pub unsafe fn from_raw_parts(data: *mut u8, len: u64, capacity: u64) -> Self { + pub unsafe fn from_raw_parts(data: *mut u8, len: i32, capacity: i32) -> Self { Self { capacity, len, @@ -126,8 +126,12 @@ impl RustBuffer { /// /// Panics if the requested size is too large to fit in an `i32`, and /// hence would risk incompatibility with some foreign-language code. - pub fn new_with_size(size: u64) -> Self { - Self::from_vec(vec![0u8; size as usize]) + pub fn new_with_size(size: usize) -> Self { + assert!( + size < i32::MAX as usize, + "RustBuffer requested size too large" + ); + Self::from_vec(vec![0u8; size]) } /// Consumes a `Vec` and returns its raw parts as a `RustBuffer`. @@ -140,8 +144,8 @@ impl RustBuffer { /// Panics if the vector's length or capacity are too large to fit in an `i32`, /// and hence would risk incompatibility with some foreign-language code. pub fn from_vec(v: Vec) -> Self { - let capacity = u64::try_from(v.capacity()).expect("buffer capacity cannot fit into a u64."); - let len = u64::try_from(v.len()).expect("buffer length cannot fit into a u64."); + let capacity = i32::try_from(v.capacity()).expect("buffer capacity cannot fit into a i32."); + let len = i32::try_from(v.len()).expect("buffer length cannot fit into a i32."); let mut v = std::mem::ManuallyDrop::new(v); unsafe { Self::from_raw_parts(v.as_mut_ptr(), len, capacity) } } @@ -194,18 +198,39 @@ impl Default for RustBuffer { } } -// Functions for the RustBuffer functionality. +// extern "C" functions for the RustBuffer functionality. // -// The scaffolding code re-exports these functions, prefixed with the component name and UDL hash -// This creates a separate set of functions for each UniFFIed component, which is needed in the -// case where we create multiple dylib artifacts since each dylib will have its own allocator. +// These are used in two ways: +// 1. Code that statically links to UniFFI can use these directly to handle RustBuffer +// allocation/destruction. The plan is to use this for the Firefox desktop JS bindings. +// +// 2. The scaffolding code re-exports these functions, prefixed with the component name and UDL +// hash This creates a separate set of functions for each UniFFIed component, which is needed +// in the case where we create multiple dylib artifacts since each dylib will have its own +// allocator. /// This helper allocates a new byte buffer owned by the Rust code, and returns it /// to the foreign-language code as a `RustBuffer` struct. Callers must eventually /// free the resulting buffer, either by explicitly calling [`uniffi_rustbuffer_free`] defined /// below, or by passing ownership of the buffer back into Rust code. -pub fn uniffi_rustbuffer_alloc(size: u64, call_status: &mut RustCallStatus) -> RustBuffer { - rust_call(call_status, || Ok(RustBuffer::new_with_size(size))) +#[cfg(feature = "extern-rustbuffer")] +#[no_mangle] +pub extern "C" fn uniffi_rustbuffer_alloc( + size: i32, + call_status: &mut RustCallStatus, +) -> RustBuffer { + _uniffi_rustbuffer_alloc(size, call_status) +} + +#[cfg(not(feature = "extern-rustbuffer"))] +pub fn uniffi_rustbuffer_alloc(size: i32, call_status: &mut RustCallStatus) -> RustBuffer { + _uniffi_rustbuffer_alloc(size, call_status) +} + +fn _uniffi_rustbuffer_alloc(size: i32, call_status: &mut RustCallStatus) -> RustBuffer { + rust_call(call_status, || { + Ok(RustBuffer::new_with_size(size.max(0) as usize)) + }) } /// This helper copies bytes owned by the foreign-language code into a new byte buffer owned @@ -216,10 +241,27 @@ pub fn uniffi_rustbuffer_alloc(size: u64, call_status: &mut RustCallStatus) -> R /// # Safety /// This function will dereference a provided pointer in order to copy bytes from it, so /// make sure the `ForeignBytes` struct contains a valid pointer and length. +#[cfg(feature = "extern-rustbuffer")] +#[no_mangle] +pub extern "C" fn uniffi_rustbuffer_from_bytes( + bytes: ForeignBytes, + call_status: &mut RustCallStatus, +) -> RustBuffer { + _uniffi_rustbuffer_from_bytes(bytes, call_status) +} + +#[cfg(not(feature = "extern-rustbuffer"))] pub fn uniffi_rustbuffer_from_bytes( bytes: ForeignBytes, call_status: &mut RustCallStatus, ) -> RustBuffer { + _uniffi_rustbuffer_from_bytes(bytes, call_status) +} + +fn _uniffi_rustbuffer_from_bytes( + bytes: ForeignBytes, + call_status: &mut RustCallStatus, +) -> RustBuffer { rust_call(call_status, || { let bytes = bytes.as_slice(); Ok(RustBuffer::from_vec(bytes.to_vec())) @@ -232,7 +274,18 @@ pub fn uniffi_rustbuffer_from_bytes( /// The argument *must* be a uniquely-owned `RustBuffer` previously obtained from a call /// into the Rust code that returned a buffer, or you'll risk freeing unowned memory or /// corrupting the allocator state. +#[cfg(feature = "extern-rustbuffer")] +#[no_mangle] +pub extern "C" fn uniffi_rustbuffer_free(buf: RustBuffer, call_status: &mut RustCallStatus) { + _uniffi_rustbuffer_free(buf, call_status) +} + +#[cfg(not(feature = "extern-rustbuffer"))] pub fn uniffi_rustbuffer_free(buf: RustBuffer, call_status: &mut RustCallStatus) { + _uniffi_rustbuffer_free(buf, call_status) +} + +fn _uniffi_rustbuffer_free(buf: RustBuffer, call_status: &mut RustCallStatus) { rust_call(call_status, || { RustBuffer::destroy(buf); Ok(()) @@ -254,9 +307,28 @@ pub fn uniffi_rustbuffer_free(buf: RustBuffer, call_status: &mut RustCallStatus) /// The first argument *must* be a uniquely-owned `RustBuffer` previously obtained from a call /// into the Rust code that returned a buffer, or you'll risk freeing unowned memory or /// corrupting the allocator state. +#[cfg(feature = "extern-rustbuffer")] +#[no_mangle] +pub extern "C" fn uniffi_rustbuffer_reserve( + buf: RustBuffer, + additional: i32, + call_status: &mut RustCallStatus, +) -> RustBuffer { + _uniffi_rustbuffer_reserve(buf, additional, call_status) +} + +#[cfg(not(feature = "extern-rustbuffer"))] pub fn uniffi_rustbuffer_reserve( buf: RustBuffer, - additional: u64, + additional: i32, + call_status: &mut RustCallStatus, +) -> RustBuffer { + _uniffi_rustbuffer_reserve(buf, additional, call_status) +} + +fn _uniffi_rustbuffer_reserve( + buf: RustBuffer, + additional: i32, call_status: &mut RustCallStatus, ) -> RustBuffer { rust_call(call_status, || { @@ -322,6 +394,24 @@ mod test { #[test] #[should_panic] + fn test_rustbuffer_provided_capacity_must_be_non_negative() { + // We guard against foreign-language code providing this kind of invalid struct. + let mut v = vec![0u8, 1, 2]; + let rbuf = unsafe { RustBuffer::from_raw_parts(v.as_mut_ptr(), 3, -7) }; + rbuf.destroy_into_vec(); + } + + #[test] + #[should_panic] + fn test_rustbuffer_provided_len_must_be_non_negative() { + // We guard against foreign-language code providing this kind of invalid struct. + let mut v = vec![0u8, 1, 2]; + let rbuf = unsafe { RustBuffer::from_raw_parts(v.as_mut_ptr(), -1, 3) }; + rbuf.destroy_into_vec(); + } + + #[test] + #[should_panic] fn test_rustbuffer_provided_len_must_not_exceed_capacity() { // We guard against foreign-language code providing this kind of invalid struct. let mut v = vec![0u8, 1, 2]; diff --git a/third_party/rust/uniffi_core/src/ffi/rustcalls.rs b/third_party/rust/uniffi_core/src/ffi/rustcalls.rs index 16b0c76f2edc..53265393c059 100644 --- a/third_party/rust/uniffi_core/src/ffi/rustcalls.rs +++ b/third_party/rust/uniffi_core/src/ffi/rustcalls.rs @@ -56,13 +56,6 @@ pub struct RustCallStatus { } impl RustCallStatus { - pub fn new() -> Self { - Self { - code: RustCallStatusCode::Success, - error_buf: MaybeUninit::new(RustBuffer::new()), - } - } - pub fn cancelled() -> Self { Self { code: RustCallStatusCode::Cancelled, @@ -109,7 +102,7 @@ pub enum RustCallStatusCode { /// Handle a scaffolding calls /// /// `callback` is responsible for making the actual Rust call and returning a special result type: -/// - For successful calls, return `Ok(value)` +/// - For successfull calls, return `Ok(value)` /// - For errors that should be translated into thrown exceptions in the foreign code, serialize /// the error into a `RustBuffer`, then return `Ok(buf)` /// - The success type, must implement `FfiDefault`. diff --git a/third_party/rust/uniffi_core/src/ffi/rustfuture.rs b/third_party/rust/uniffi_core/src/ffi/rustfuture.rs new file mode 100644 index 000000000000..0c1a24174bbc --- /dev/null +++ b/third_party/rust/uniffi_core/src/ffi/rustfuture.rs @@ -0,0 +1,735 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! [`RustFuture`] represents a [`Future`] that can be sent to the foreign code over FFI. +//! +//! This type is not instantiated directly, but via the procedural macros, such as `#[uniffi::export]`. +//! +//! # The big picture +//! +//! We implement async foreign functions using a simplified version of the Future API: +//! +//! 0. At startup, register a [RustFutureContinuationCallback] by calling +//! rust_future_continuation_callback_set. +//! 1. Call the scaffolding function to get a [RustFutureHandle] +//! 2a. In a loop: +//! - Call [rust_future_poll] +//! - Suspend the function until the [rust_future_poll] continuation function is called +//! - If the continuation was function was called with [RustFuturePoll::Ready], then break +//! otherwise continue. +//! 2b. If the async function is cancelled, then call [rust_future_cancel]. This causes the +//! continuation function to be called with [RustFuturePoll::Ready] and the [RustFuture] to +//! enter a cancelled state. +//! 3. Call [rust_future_complete] to get the result of the future. +//! 4. Call [rust_future_free] to free the future, ideally in a finally block. This: +//! - Releases any resources held by the future +//! - Calls any continuation callbacks that have not been called yet +//! +//! Note: Technically, the foreign code calls the scaffolding versions of the `rust_future_*` +//! functions. These are generated by the scaffolding macro, specially prefixed, and extern "C", +//! and manually monomorphized in the case of [rust_future_complete]. See +//! `uniffi_macros/src/setup_scaffolding.rs` for details. +//! +//! ## How does `Future` work exactly? +//! +//! A [`Future`] in Rust does nothing. When calling an async function, it just +//! returns a `Future` but nothing has happened yet. To start the computation, +//! the future must be polled. It returns [`Poll::Ready(r)`][`Poll::Ready`] if +//! the result is ready, [`Poll::Pending`] otherwise. `Poll::Pending` basically +//! means: +//! +//! > Please, try to poll me later, maybe the result will be ready! +//! +//! This model is very different than what other languages do, but it can actually +//! be translated quite easily, fortunately for us! +//! +//! But… wait a minute… who is responsible to poll the `Future` if a `Future` does +//! nothing? Well, it's _the executor_. The executor is responsible _to drive_ the +//! `Future`: that's where they are polled. +//! +//! But… wait another minute… how does the executor know when to poll a [`Future`]? +//! Does it poll them randomly in an endless loop? Well, no, actually it depends +//! on the executor! A well-designed `Future` and executor work as follows. +//! Normally, when [`Future::poll`] is called, a [`Context`] argument is +//! passed to it. It contains a [`Waker`]. The [`Waker`] is built on top of a +//! [`RawWaker`] which implements whatever is necessary. Usually, a waker will +//! signal the executor to poll a particular `Future`. A `Future` will clone +//! or pass-by-ref the waker to somewhere, as a callback, a completion, a +//! function, or anything, to the system that is responsible to notify when a +//! task is completed. So, to recap, the waker is _not_ responsible for waking the +//! `Future`, it _is_ responsible for _signaling_ the executor that a particular +//! `Future` should be polled again. That's why the documentation of +//! [`Poll::Pending`] specifies: +//! +//! > When a function returns `Pending`, the function must also ensure that the +//! > current task is scheduled to be awoken when progress can be made. +//! +//! “awakening” is done by using the `Waker`. +//! +//! [`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html +//! [`Future::poll`]: https://doc.rust-lang.org/std/future/trait.Future.html#tymethod.poll +//! [`Pol::Ready`]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Ready +//! [`Poll::Pending`]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Pending +//! [`Context`]: https://doc.rust-lang.org/std/task/struct.Context.html +//! [`Waker`]: https://doc.rust-lang.org/std/task/struct.Waker.html +//! [`RawWaker`]: https://doc.rust-lang.org/std/task/struct.RawWaker.html + +use std::{ + future::Future, + marker::PhantomData, + mem, + ops::Deref, + panic, + pin::Pin, + sync::{Arc, Mutex}, + task::{Context, Poll, Wake}, +}; + +use crate::{rust_call_with_out_status, FfiDefault, LowerReturn, RustCallStatus}; + +/// Result code for [rust_future_poll]. This is passed to the continuation function. +#[repr(i8)] +#[derive(Debug, PartialEq, Eq)] +pub enum RustFuturePoll { + /// The future is ready and is waiting for [rust_future_complete] to be called + Ready = 0, + /// The future might be ready and [rust_future_poll] should be called again + MaybeReady = 1, +} + +/// Foreign callback that's passed to [rust_future_poll] +/// +/// The Rust side of things calls this when the foreign side should call [rust_future_poll] again +/// to continue progress on the future. +pub type RustFutureContinuationCallback = extern "C" fn(callback_data: *const (), RustFuturePoll); + +/// Opaque handle for a Rust future that's stored by the foreign language code +#[repr(transparent)] +pub struct RustFutureHandle(*const ()); + +// === Public FFI API === + +/// Create a new [RustFutureHandle] +/// +/// For each exported async function, UniFFI will create a scaffolding function that uses this to +/// create the [RustFutureHandle] to pass to the foreign code. +pub fn rust_future_new(future: F, tag: UT) -> RustFutureHandle +where + // F is the future type returned by the exported async function. It needs to be Send + `static + // since it will move between threads for an indeterminate amount of time as the foreign + // executor calls polls it and the Rust executor wakes it. It does not need to by `Sync`, + // since we synchronize all access to the values. + F: Future + Send + 'static, + // T is the output of the Future. It needs to implement [LowerReturn]. Also it must be Send + + // 'static for the same reason as F. + T: LowerReturn + Send + 'static, + // The UniFfiTag ZST. The Send + 'static bound is to keep rustc happy. + UT: Send + 'static, +{ + // Create a RustFuture and coerce to `Arc`, which is what we use to + // implement the FFI + let future_ffi = RustFuture::new(future, tag) as Arc>; + // Box the Arc, to convert the wide pointer into a normal sized pointer so that we can pass it + // to the foreign code. + let boxed_ffi = Box::new(future_ffi); + // We can now create a RustFutureHandle + RustFutureHandle(Box::into_raw(boxed_ffi) as *mut ()) +} + +/// Poll a Rust future +/// +/// When the future is ready to progress the continuation will be called with the `data` value and +/// a [RustFuturePoll] value. For each [rust_future_poll] call the continuation will be called +/// exactly once. +/// +/// # Safety +/// +/// The [RustFutureHandle] must not previously have been passed to [rust_future_free] +pub unsafe fn rust_future_poll( + handle: RustFutureHandle, + callback: RustFutureContinuationCallback, + data: *const (), +) { + let future = &*(handle.0 as *mut Arc>); + future.clone().ffi_poll(callback, data) +} + +/// Cancel a Rust future +/// +/// Any current and future continuations will be immediately called with RustFuturePoll::Ready. +/// +/// This is needed for languages like Swift, which continuation to wait for the continuation to be +/// called when tasks are cancelled. +/// +/// # Safety +/// +/// The [RustFutureHandle] must not previously have been passed to [rust_future_free] +pub unsafe fn rust_future_cancel(handle: RustFutureHandle) { + let future = &*(handle.0 as *mut Arc>); + future.clone().ffi_cancel() +} + +/// Complete a Rust future +/// +/// Note: the actually extern "C" scaffolding functions can't be generic, so we generate one for +/// each supported FFI type. +/// +/// # Safety +/// +/// - The [RustFutureHandle] must not previously have been passed to [rust_future_free] +/// - The `T` param must correctly correspond to the [rust_future_new] call. It must +/// be `>::ReturnType` +pub unsafe fn rust_future_complete( + handle: RustFutureHandle, + out_status: &mut RustCallStatus, +) -> ReturnType { + let future = &*(handle.0 as *mut Arc>); + future.ffi_complete(out_status) +} + +/// Free a Rust future, dropping the strong reference and releasing all references held by the +/// future. +/// +/// # Safety +/// +/// The [RustFutureHandle] must not previously have been passed to [rust_future_free] +pub unsafe fn rust_future_free(handle: RustFutureHandle) { + let future = Box::from_raw(handle.0 as *mut Arc>); + future.ffi_free() +} + +/// Thread-safe storage for [RustFutureContinuationCallback] data +/// +/// The basic guarantee is that all data pointers passed in are passed out exactly once to the +/// foreign continuation callback. This enables us to uphold the [rust_future_poll] guarantee. +/// +/// [ContinuationDataCell] also tracks cancellation, which is closely tied to continuation data. +#[derive(Debug)] +enum ContinuationDataCell { + /// No continuations set, neither wake() nor cancel() called. + Empty, + /// `wake()` was called when there was no continuation set. The next time `store` is called, + /// the continuation should be immediately invoked with `RustFuturePoll::MaybeReady` + Waked, + /// The future has been cancelled, any future `store` calls should immediately result in the + /// continuation being called with `RustFuturePoll::Ready`. + Cancelled, + /// Continuation set, the next time `wake()` is called is called, we should invoke it. + Set(RustFutureContinuationCallback, *const ()), +} + +impl ContinuationDataCell { + fn new() -> Self { + Self::Empty + } + + /// Store new continuation data if we are in the `Empty` state. If we are in the `Waked` or + /// `Cancelled` state, call the continuation immediately with the data. + fn store(&mut self, callback: RustFutureContinuationCallback, data: *const ()) { + match self { + Self::Empty => *self = Self::Set(callback, data), + Self::Set(old_callback, old_data) => { + log::error!( + "store: observed `Self::Set` state. Is poll() being called from multiple threads at once?" + ); + old_callback(*old_data, RustFuturePoll::Ready); + *self = Self::Set(callback, data); + } + Self::Waked => { + *self = Self::Empty; + callback(data, RustFuturePoll::MaybeReady); + } + Self::Cancelled => { + callback(data, RustFuturePoll::Ready); + } + } + } + + fn wake(&mut self) { + match self { + // If we had a continuation set, then call it and transition to the `Empty` state. + Self::Set(callback, old_data) => { + let old_data = *old_data; + let callback = *callback; + *self = Self::Empty; + callback(old_data, RustFuturePoll::MaybeReady); + } + // If we were in the `Empty` state, then transition to `Waked`. The next time `store` + // is called, we will immediately call the continuation. + Self::Empty => *self = Self::Waked, + // This is a no-op if we were in the `Cancelled` or `Waked` state. + _ => (), + } + } + + fn cancel(&mut self) { + if let Self::Set(callback, old_data) = mem::replace(self, Self::Cancelled) { + callback(old_data, RustFuturePoll::Ready); + } + } + + fn is_cancelled(&self) -> bool { + matches!(self, Self::Cancelled) + } +} + +// ContinuationDataCell is Send + Sync as long we handle the *const () pointer correctly + +unsafe impl Send for ContinuationDataCell {} +unsafe impl Sync for ContinuationDataCell {} + +/// Wraps the actual future we're polling +struct WrappedFuture +where + // See rust_future_new for an explanation of these trait bounds + F: Future + Send + 'static, + T: LowerReturn + Send + 'static, + UT: Send + 'static, +{ + // Note: this could be a single enum, but that would make it easy to mess up the future pinning + // guarantee. For example you might want to call `std::mem::take()` to try to get the result, + // but if the future happened to be stored that would move and break all internal references. + future: Option, + result: Option>, +} + +impl WrappedFuture +where + // See rust_future_new for an explanation of these trait bounds + F: Future + Send + 'static, + T: LowerReturn + Send + 'static, + UT: Send + 'static, +{ + fn new(future: F) -> Self { + Self { + future: Some(future), + result: None, + } + } + + // Poll the future and check if it's ready or not + fn poll(&mut self, context: &mut Context<'_>) -> bool { + if self.result.is_some() { + true + } else if let Some(future) = &mut self.future { + // SAFETY: We can call Pin::new_unchecked because: + // - This is the only time we get a &mut to `self.future` + // - We never poll the future after it's moved (for example by using take()) + // - We never move RustFuture, which contains us. + // - RustFuture is private to this module so no other code can move it. + let pinned = unsafe { Pin::new_unchecked(future) }; + // Run the poll and lift the result if it's ready + let mut out_status = RustCallStatus::default(); + let result: Option> = rust_call_with_out_status( + &mut out_status, + // This closure uses a `&mut F` value, which means it's not UnwindSafe by + // default. If the future panics, it may be in an invalid state. + // + // However, we can safely use `AssertUnwindSafe` since a panic will lead the `None` + // case below and we will never poll the future again. + panic::AssertUnwindSafe(|| match pinned.poll(context) { + Poll::Pending => Ok(Poll::Pending), + Poll::Ready(v) => T::lower_return(v).map(Poll::Ready), + }), + ); + match result { + Some(Poll::Pending) => false, + Some(Poll::Ready(v)) => { + self.future = None; + self.result = Some(Ok(v)); + true + } + None => { + self.future = None; + self.result = Some(Err(out_status)); + true + } + } + } else { + log::error!("poll with neither future nor result set"); + true + } + } + + fn complete(&mut self, out_status: &mut RustCallStatus) -> T::ReturnType { + let mut return_value = T::ReturnType::ffi_default(); + match self.result.take() { + Some(Ok(v)) => return_value = v, + Some(Err(call_status)) => *out_status = call_status, + None => *out_status = RustCallStatus::cancelled(), + } + self.free(); + return_value + } + + fn free(&mut self) { + self.future = None; + self.result = None; + } +} + +// If F and T are Send, then WrappedFuture is too +// +// Rust will not mark it Send by default when T::ReturnType is a raw pointer. This is promising +// that we will treat the raw pointer properly, for example by not returning it twice. +unsafe impl Send for WrappedFuture +where + // See rust_future_new for an explanation of these trait bounds + F: Future + Send + 'static, + T: LowerReturn + Send + 'static, + UT: Send + 'static, +{ +} + +/// Future that the foreign code is awaiting +struct RustFuture +where + // See rust_future_new for an explanation of these trait bounds + F: Future + Send + 'static, + T: LowerReturn + Send + 'static, + UT: Send + 'static, +{ + // This Mutex should never block if our code is working correctly, since there should not be + // multiple threads calling [Self::poll] and/or [Self::complete] at the same time. + future: Mutex>, + continuation_data: Mutex, + // UT is used as the generic parameter for [LowerReturn]. + // Let's model this with PhantomData as a function that inputs a UT value. + _phantom: PhantomData ()>, +} + +impl RustFuture +where + // See rust_future_new for an explanation of these trait bounds + F: Future + Send + 'static, + T: LowerReturn + Send + 'static, + UT: Send + 'static, +{ + fn new(future: F, _tag: UT) -> Arc { + Arc::new(Self { + future: Mutex::new(WrappedFuture::new(future)), + continuation_data: Mutex::new(ContinuationDataCell::new()), + _phantom: PhantomData, + }) + } + + fn poll(self: Arc, callback: RustFutureContinuationCallback, data: *const ()) { + let ready = self.is_cancelled() || { + let mut locked = self.future.lock().unwrap(); + let waker: std::task::Waker = Arc::clone(&self).into(); + locked.poll(&mut Context::from_waker(&waker)) + }; + if ready { + callback(data, RustFuturePoll::Ready) + } else { + self.continuation_data.lock().unwrap().store(callback, data); + } + } + + fn is_cancelled(&self) -> bool { + self.continuation_data.lock().unwrap().is_cancelled() + } + + fn wake(&self) { + self.continuation_data.lock().unwrap().wake(); + } + + fn cancel(&self) { + self.continuation_data.lock().unwrap().cancel(); + } + + fn complete(&self, call_status: &mut RustCallStatus) -> T::ReturnType { + self.future.lock().unwrap().complete(call_status) + } + + fn free(self: Arc) { + // Call cancel() to send any leftover data to the continuation callback + self.continuation_data.lock().unwrap().cancel(); + // Ensure we drop our inner future, releasing all held references + self.future.lock().unwrap().free(); + } +} + +impl Wake for RustFuture +where + // See rust_future_new for an explanation of these trait bounds + F: Future + Send + 'static, + T: LowerReturn + Send + 'static, + UT: Send + 'static, +{ + fn wake(self: Arc) { + self.deref().wake() + } + + fn wake_by_ref(self: &Arc) { + self.deref().wake() + } +} + +/// RustFuture FFI trait. This allows `Arc>` to be cast to +/// `Arc>`, which is needed to implement the public FFI API. In particular, this +/// allows you to use RustFuture functionality without knowing the concrete Future type, which is +/// unnamable. +/// +/// This is parametrized on the ReturnType rather than the `T` directly, to reduce the number of +/// scaffolding functions we need to generate. If it was parametrized on `T`, then we would need +/// to create a poll, cancel, complete, and free scaffolding function for each exported async +/// function. That would add ~1kb binary size per exported function based on a quick estimate on a +/// x86-64 machine . By parametrizing on `T::ReturnType` we can instead monomorphize by hand and +/// only create those functions for each of the 13 possible FFI return types. +#[doc(hidden)] +trait RustFutureFfi { + fn ffi_poll(self: Arc, callback: RustFutureContinuationCallback, data: *const ()); + fn ffi_cancel(&self); + fn ffi_complete(&self, call_status: &mut RustCallStatus) -> ReturnType; + fn ffi_free(self: Arc); +} + +impl RustFutureFfi for RustFuture +where + // See rust_future_new for an explanation of these trait bounds + F: Future + Send + 'static, + T: LowerReturn + Send + 'static, + UT: Send + 'static, +{ + fn ffi_poll(self: Arc, callback: RustFutureContinuationCallback, data: *const ()) { + self.poll(callback, data) + } + + fn ffi_cancel(&self) { + self.cancel() + } + + fn ffi_complete(&self, call_status: &mut RustCallStatus) -> T::ReturnType { + self.complete(call_status) + } + + fn ffi_free(self: Arc) { + self.free(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{test_util::TestError, Lift, RustBuffer, RustCallStatusCode}; + use once_cell::sync::OnceCell; + use std::task::Waker; + + // Sender/Receiver pair that we use for testing + struct Channel { + result: Option>, + waker: Option, + } + + struct Sender(Arc>); + + impl Sender { + fn wake(&self) { + let inner = self.0.lock().unwrap(); + if let Some(waker) = &inner.waker { + waker.wake_by_ref(); + } + } + + fn send(&self, value: Result) { + let mut inner = self.0.lock().unwrap(); + if inner.result.replace(value).is_some() { + panic!("value already sent"); + } + if let Some(waker) = &inner.waker { + waker.wake_by_ref(); + } + } + } + + struct Receiver(Arc>); + + impl Future for Receiver { + type Output = Result; + + fn poll( + self: Pin<&mut Self>, + context: &mut Context<'_>, + ) -> Poll> { + let mut inner = self.0.lock().unwrap(); + match &inner.result { + Some(v) => Poll::Ready(v.clone()), + None => { + inner.waker = Some(context.waker().clone()); + Poll::Pending + } + } + } + } + + // Create a sender and rust future that we can use for testing + fn channel() -> (Sender, Arc>) { + let channel = Arc::new(Mutex::new(Channel { + result: None, + waker: None, + })); + let rust_future = RustFuture::new(Receiver(channel.clone()), crate::UniFfiTag); + (Sender(channel), rust_future) + } + + /// Poll a Rust future and get an OnceCell that's set when the continuation is called + fn poll(rust_future: &Arc>) -> Arc> { + let cell = Arc::new(OnceCell::new()); + let cell_ptr = Arc::into_raw(cell.clone()) as *const (); + rust_future.clone().ffi_poll(poll_continuation, cell_ptr); + cell + } + + extern "C" fn poll_continuation(data: *const (), code: RustFuturePoll) { + let cell = unsafe { Arc::from_raw(data as *const OnceCell) }; + cell.set(code).expect("Error setting OnceCell"); + } + + fn complete(rust_future: Arc>) -> (RustBuffer, RustCallStatus) { + let mut out_status_code = RustCallStatus::default(); + let return_value = rust_future.ffi_complete(&mut out_status_code); + (return_value, out_status_code) + } + + #[test] + fn test_success() { + let (sender, rust_future) = channel(); + + // Test polling the rust future before it's ready + let continuation_result = poll(&rust_future); + assert_eq!(continuation_result.get(), None); + sender.wake(); + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::MaybeReady)); + + // Test polling the rust future when it's ready + let continuation_result = poll(&rust_future); + assert_eq!(continuation_result.get(), None); + sender.send(Ok("All done".into())); + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::MaybeReady)); + + // Future polls should immediately return ready + let continuation_result = poll(&rust_future); + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); + + // Complete the future + let (return_buf, call_status) = complete(rust_future); + assert_eq!(call_status.code, RustCallStatusCode::Success); + assert_eq!( + >::try_lift(return_buf).unwrap(), + "All done" + ); + } + + #[test] + fn test_error() { + let (sender, rust_future) = channel(); + + let continuation_result = poll(&rust_future); + assert_eq!(continuation_result.get(), None); + sender.send(Err("Something went wrong".into())); + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::MaybeReady)); + + let continuation_result = poll(&rust_future); + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); + + let (_, call_status) = complete(rust_future); + assert_eq!(call_status.code, RustCallStatusCode::Error); + unsafe { + assert_eq!( + >::try_lift_from_rust_buffer( + call_status.error_buf.assume_init() + ) + .unwrap(), + TestError::from("Something went wrong"), + ) + } + } + + // Once `complete` is called, the inner future should be released, even if wakers still hold a + // reference to the RustFuture + #[test] + fn test_cancel() { + let (_sender, rust_future) = channel(); + + let continuation_result = poll(&rust_future); + assert_eq!(continuation_result.get(), None); + rust_future.ffi_cancel(); + // Cancellation should immediately invoke the callback with RustFuturePoll::Ready + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); + + // Future polls should immediately invoke the callback with RustFuturePoll::Ready + let continuation_result = poll(&rust_future); + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); + + let (_, call_status) = complete(rust_future); + assert_eq!(call_status.code, RustCallStatusCode::Cancelled); + } + + // Once `free` is called, the inner future should be released, even if wakers still hold a + // reference to the RustFuture + #[test] + fn test_release_future() { + let (sender, rust_future) = channel(); + // Create a weak reference to the channel to use to check if rust_future has dropped its + // future. + let channel_weak = Arc::downgrade(&sender.0); + drop(sender); + // Create an extra ref to rust_future, simulating a waker that still holds a reference to + // it + let rust_future2 = rust_future.clone(); + + // Complete the rust future + rust_future.ffi_free(); + // Even though rust_future is still alive, the channel shouldn't be + assert!(Arc::strong_count(&rust_future2) > 0); + assert_eq!(channel_weak.strong_count(), 0); + assert!(channel_weak.upgrade().is_none()); + } + + // If `free` is called with a continuation still stored, we should call it them then. + // + // This shouldn't happen in practice, but it seems like good defensive programming + #[test] + fn test_complete_with_stored_continuation() { + let (_sender, rust_future) = channel(); + + let continuation_result = poll(&rust_future); + rust_future.ffi_free(); + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); + } + + // Test what happens if we see a `wake()` call while we're polling the future. This can + // happen, for example, with futures that are handled by a tokio thread pool. We should + // schedule another poll of the future in this case. + #[test] + fn test_wake_during_poll() { + let mut first_time = true; + let future = std::future::poll_fn(move |ctx| { + if first_time { + first_time = false; + // Wake the future while we are in the middle of polling it + ctx.waker().clone().wake(); + Poll::Pending + } else { + // The second time we're polled, we're ready + Poll::Ready("All done".to_owned()) + } + }); + let rust_future: Arc> = + RustFuture::new(future, crate::UniFfiTag); + let continuation_result = poll(&rust_future); + // The continuation function should called immediately + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::MaybeReady)); + // A second poll should finish the future + let continuation_result = poll(&rust_future); + assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); + let (return_buf, call_status) = complete(rust_future); + assert_eq!(call_status.code, RustCallStatusCode::Success); + assert_eq!( + >::try_lift(return_buf).unwrap(), + "All done" + ); + } +} diff --git a/third_party/rust/uniffi_core/src/ffi/rustfuture/future.rs b/third_party/rust/uniffi_core/src/ffi/rustfuture/future.rs deleted file mode 100644 index 93c34e7543c4..000000000000 --- a/third_party/rust/uniffi_core/src/ffi/rustfuture/future.rs +++ /dev/null @@ -1,320 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//! [`RustFuture`] represents a [`Future`] that can be sent to the foreign code over FFI. -//! -//! This type is not instantiated directly, but via the procedural macros, such as `#[uniffi::export]`. -//! -//! # The big picture -//! -//! We implement async foreign functions using a simplified version of the Future API: -//! -//! 0. At startup, register a [RustFutureContinuationCallback] by calling -//! rust_future_continuation_callback_set. -//! 1. Call the scaffolding function to get a [Handle] -//! 2a. In a loop: -//! - Call [rust_future_poll] -//! - Suspend the function until the [rust_future_poll] continuation function is called -//! - If the continuation was function was called with [RustFuturePoll::Ready], then break -//! otherwise continue. -//! 2b. If the async function is cancelled, then call [rust_future_cancel]. This causes the -//! continuation function to be called with [RustFuturePoll::Ready] and the [RustFuture] to -//! enter a cancelled state. -//! 3. Call [rust_future_complete] to get the result of the future. -//! 4. Call [rust_future_free] to free the future, ideally in a finally block. This: -//! - Releases any resources held by the future -//! - Calls any continuation callbacks that have not been called yet -//! -//! Note: Technically, the foreign code calls the scaffolding versions of the `rust_future_*` -//! functions. These are generated by the scaffolding macro, specially prefixed, and extern "C", -//! and manually monomorphized in the case of [rust_future_complete]. See -//! `uniffi_macros/src/setup_scaffolding.rs` for details. -//! -//! ## How does `Future` work exactly? -//! -//! A [`Future`] in Rust does nothing. When calling an async function, it just -//! returns a `Future` but nothing has happened yet. To start the computation, -//! the future must be polled. It returns [`Poll::Ready(r)`][`Poll::Ready`] if -//! the result is ready, [`Poll::Pending`] otherwise. `Poll::Pending` basically -//! means: -//! -//! > Please, try to poll me later, maybe the result will be ready! -//! -//! This model is very different than what other languages do, but it can actually -//! be translated quite easily, fortunately for us! -//! -//! But… wait a minute… who is responsible to poll the `Future` if a `Future` does -//! nothing? Well, it's _the executor_. The executor is responsible _to drive_ the -//! `Future`: that's where they are polled. -//! -//! But… wait another minute… how does the executor know when to poll a [`Future`]? -//! Does it poll them randomly in an endless loop? Well, no, actually it depends -//! on the executor! A well-designed `Future` and executor work as follows. -//! Normally, when [`Future::poll`] is called, a [`Context`] argument is -//! passed to it. It contains a [`Waker`]. The [`Waker`] is built on top of a -//! [`RawWaker`] which implements whatever is necessary. Usually, a waker will -//! signal the executor to poll a particular `Future`. A `Future` will clone -//! or pass-by-ref the waker to somewhere, as a callback, a completion, a -//! function, or anything, to the system that is responsible to notify when a -//! task is completed. So, to recap, the waker is _not_ responsible for waking the -//! `Future`, it _is_ responsible for _signaling_ the executor that a particular -//! `Future` should be polled again. That's why the documentation of -//! [`Poll::Pending`] specifies: -//! -//! > When a function returns `Pending`, the function must also ensure that the -//! > current task is scheduled to be awoken when progress can be made. -//! -//! “awakening” is done by using the `Waker`. -//! -//! [`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html -//! [`Future::poll`]: https://doc.rust-lang.org/std/future/trait.Future.html#tymethod.poll -//! [`Pol::Ready`]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Ready -//! [`Poll::Pending`]: https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Pending -//! [`Context`]: https://doc.rust-lang.org/std/task/struct.Context.html -//! [`Waker`]: https://doc.rust-lang.org/std/task/struct.Waker.html -//! [`RawWaker`]: https://doc.rust-lang.org/std/task/struct.RawWaker.html - -use std::{ - future::Future, - marker::PhantomData, - ops::Deref, - panic, - pin::Pin, - sync::{Arc, Mutex}, - task::{Context, Poll, Wake}, -}; - -use super::{RustFutureContinuationCallback, RustFuturePoll, Scheduler}; -use crate::{rust_call_with_out_status, FfiDefault, LowerReturn, RustCallStatus}; - -/// Wraps the actual future we're polling -struct WrappedFuture -where - // See rust_future_new for an explanation of these trait bounds - F: Future + Send + 'static, - T: LowerReturn + Send + 'static, - UT: Send + 'static, -{ - // Note: this could be a single enum, but that would make it easy to mess up the future pinning - // guarantee. For example you might want to call `std::mem::take()` to try to get the result, - // but if the future happened to be stored that would move and break all internal references. - future: Option, - result: Option>, -} - -impl WrappedFuture -where - // See rust_future_new for an explanation of these trait bounds - F: Future + Send + 'static, - T: LowerReturn + Send + 'static, - UT: Send + 'static, -{ - fn new(future: F) -> Self { - Self { - future: Some(future), - result: None, - } - } - - // Poll the future and check if it's ready or not - fn poll(&mut self, context: &mut Context<'_>) -> bool { - if self.result.is_some() { - true - } else if let Some(future) = &mut self.future { - // SAFETY: We can call Pin::new_unchecked because: - // - This is the only time we get a &mut to `self.future` - // - We never poll the future after it's moved (for example by using take()) - // - We never move RustFuture, which contains us. - // - RustFuture is private to this module so no other code can move it. - let pinned = unsafe { Pin::new_unchecked(future) }; - // Run the poll and lift the result if it's ready - let mut out_status = RustCallStatus::default(); - let result: Option> = rust_call_with_out_status( - &mut out_status, - // This closure uses a `&mut F` value, which means it's not UnwindSafe by - // default. If the future panics, it may be in an invalid state. - // - // However, we can safely use `AssertUnwindSafe` since a panic will lead the `None` - // case below and we will never poll the future again. - panic::AssertUnwindSafe(|| match pinned.poll(context) { - Poll::Pending => Ok(Poll::Pending), - Poll::Ready(v) => T::lower_return(v).map(Poll::Ready), - }), - ); - match result { - Some(Poll::Pending) => false, - Some(Poll::Ready(v)) => { - self.future = None; - self.result = Some(Ok(v)); - true - } - None => { - self.future = None; - self.result = Some(Err(out_status)); - true - } - } - } else { - log::error!("poll with neither future nor result set"); - true - } - } - - fn complete(&mut self, out_status: &mut RustCallStatus) -> T::ReturnType { - let mut return_value = T::ReturnType::ffi_default(); - match self.result.take() { - Some(Ok(v)) => return_value = v, - Some(Err(call_status)) => *out_status = call_status, - None => *out_status = RustCallStatus::cancelled(), - } - self.free(); - return_value - } - - fn free(&mut self) { - self.future = None; - self.result = None; - } -} - -// If F and T are Send, then WrappedFuture is too -// -// Rust will not mark it Send by default when T::ReturnType is a raw pointer. This is promising -// that we will treat the raw pointer properly, for example by not returning it twice. -unsafe impl Send for WrappedFuture -where - // See rust_future_new for an explanation of these trait bounds - F: Future + Send + 'static, - T: LowerReturn + Send + 'static, - UT: Send + 'static, -{ -} - -/// Future that the foreign code is awaiting -pub(super) struct RustFuture -where - // See rust_future_new for an explanation of these trait bounds - F: Future + Send + 'static, - T: LowerReturn + Send + 'static, - UT: Send + 'static, -{ - // This Mutex should never block if our code is working correctly, since there should not be - // multiple threads calling [Self::poll] and/or [Self::complete] at the same time. - future: Mutex>, - scheduler: Mutex, - // UT is used as the generic parameter for [LowerReturn]. - // Let's model this with PhantomData as a function that inputs a UT value. - _phantom: PhantomData ()>, -} - -impl RustFuture -where - // See rust_future_new for an explanation of these trait bounds - F: Future + Send + 'static, - T: LowerReturn + Send + 'static, - UT: Send + 'static, -{ - pub(super) fn new(future: F, _tag: UT) -> Arc { - Arc::new(Self { - future: Mutex::new(WrappedFuture::new(future)), - scheduler: Mutex::new(Scheduler::new()), - _phantom: PhantomData, - }) - } - - pub(super) fn poll(self: Arc, callback: RustFutureContinuationCallback, data: u64) { - let ready = self.is_cancelled() || { - let mut locked = self.future.lock().unwrap(); - let waker: std::task::Waker = Arc::clone(&self).into(); - locked.poll(&mut Context::from_waker(&waker)) - }; - if ready { - callback(data, RustFuturePoll::Ready) - } else { - self.scheduler.lock().unwrap().store(callback, data); - } - } - - pub(super) fn is_cancelled(&self) -> bool { - self.scheduler.lock().unwrap().is_cancelled() - } - - pub(super) fn wake(&self) { - self.scheduler.lock().unwrap().wake(); - } - - pub(super) fn cancel(&self) { - self.scheduler.lock().unwrap().cancel(); - } - - pub(super) fn complete(&self, call_status: &mut RustCallStatus) -> T::ReturnType { - self.future.lock().unwrap().complete(call_status) - } - - pub(super) fn free(self: Arc) { - // Call cancel() to send any leftover data to the continuation callback - self.scheduler.lock().unwrap().cancel(); - // Ensure we drop our inner future, releasing all held references - self.future.lock().unwrap().free(); - } -} - -impl Wake for RustFuture -where - // See rust_future_new for an explanation of these trait bounds - F: Future + Send + 'static, - T: LowerReturn + Send + 'static, - UT: Send + 'static, -{ - fn wake(self: Arc) { - self.deref().wake() - } - - fn wake_by_ref(self: &Arc) { - self.deref().wake() - } -} - -/// RustFuture FFI trait. This allows `Arc>` to be cast to -/// `Arc>`, which is needed to implement the public FFI API. In particular, this -/// allows you to use RustFuture functionality without knowing the concrete Future type, which is -/// unnamable. -/// -/// This is parametrized on the ReturnType rather than the `T` directly, to reduce the number of -/// scaffolding functions we need to generate. If it was parametrized on `T`, then we would need -/// to create a poll, cancel, complete, and free scaffolding function for each exported async -/// function. That would add ~1kb binary size per exported function based on a quick estimate on a -/// x86-64 machine . By parametrizing on `T::ReturnType` we can instead monomorphize by hand and -/// only create those functions for each of the 13 possible FFI return types. -#[doc(hidden)] -pub trait RustFutureFfi: Send + Sync { - fn ffi_poll(self: Arc, callback: RustFutureContinuationCallback, data: u64); - fn ffi_cancel(&self); - fn ffi_complete(&self, call_status: &mut RustCallStatus) -> ReturnType; - fn ffi_free(self: Arc); -} - -impl RustFutureFfi for RustFuture -where - // See rust_future_new for an explanation of these trait bounds - F: Future + Send + 'static, - T: LowerReturn + Send + 'static, - UT: Send + 'static, -{ - fn ffi_poll(self: Arc, callback: RustFutureContinuationCallback, data: u64) { - self.poll(callback, data) - } - - fn ffi_cancel(&self) { - self.cancel() - } - - fn ffi_complete(&self, call_status: &mut RustCallStatus) -> T::ReturnType { - self.complete(call_status) - } - - fn ffi_free(self: Arc) { - self.free(); - } -} diff --git a/third_party/rust/uniffi_core/src/ffi/rustfuture/mod.rs b/third_party/rust/uniffi_core/src/ffi/rustfuture/mod.rs deleted file mode 100644 index 3d3505e5ef11..000000000000 --- a/third_party/rust/uniffi_core/src/ffi/rustfuture/mod.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use std::{future::Future, sync::Arc}; - -mod future; -mod scheduler; -use future::*; -use scheduler::*; - -#[cfg(test)] -mod tests; - -use crate::{derive_ffi_traits, Handle, HandleAlloc, LowerReturn, RustCallStatus}; - -/// Result code for [rust_future_poll]. This is passed to the continuation function. -#[repr(i8)] -#[derive(Debug, PartialEq, Eq)] -pub enum RustFuturePoll { - /// The future is ready and is waiting for [rust_future_complete] to be called - Ready = 0, - /// The future might be ready and [rust_future_poll] should be called again - MaybeReady = 1, -} - -/// Foreign callback that's passed to [rust_future_poll] -/// -/// The Rust side of things calls this when the foreign side should call [rust_future_poll] again -/// to continue progress on the future. -pub type RustFutureContinuationCallback = extern "C" fn(callback_data: u64, RustFuturePoll); - -// === Public FFI API === - -/// Create a new [Handle] for a Rust future -/// -/// For each exported async function, UniFFI will create a scaffolding function that uses this to -/// create the [Handle] to pass to the foreign code. -pub fn rust_future_new(future: F, tag: UT) -> Handle -where - // F is the future type returned by the exported async function. It needs to be Send + `static - // since it will move between threads for an indeterminate amount of time as the foreign - // executor calls polls it and the Rust executor wakes it. It does not need to by `Sync`, - // since we synchronize all access to the values. - F: Future + Send + 'static, - // T is the output of the Future. It needs to implement [LowerReturn]. Also it must be Send + - // 'static for the same reason as F. - T: LowerReturn + Send + 'static, - // The UniFfiTag ZST. The Send + 'static bound is to keep rustc happy. - UT: Send + 'static, - // Needed to allocate a handle - dyn RustFutureFfi: HandleAlloc, -{ - as HandleAlloc>::new_handle( - RustFuture::new(future, tag) as Arc> - ) -} - -/// Poll a Rust future -/// -/// When the future is ready to progress the continuation will be called with the `data` value and -/// a [RustFuturePoll] value. For each [rust_future_poll] call the continuation will be called -/// exactly once. -/// -/// # Safety -/// -/// The [Handle] must not previously have been passed to [rust_future_free] -pub unsafe fn rust_future_poll( - handle: Handle, - callback: RustFutureContinuationCallback, - data: u64, -) where - dyn RustFutureFfi: HandleAlloc, -{ - as HandleAlloc>::get_arc(handle).ffi_poll(callback, data) -} - -/// Cancel a Rust future -/// -/// Any current and future continuations will be immediately called with RustFuturePoll::Ready. -/// -/// This is needed for languages like Swift, which continuation to wait for the continuation to be -/// called when tasks are cancelled. -/// -/// # Safety -/// -/// The [Handle] must not previously have been passed to [rust_future_free] -pub unsafe fn rust_future_cancel(handle: Handle) -where - dyn RustFutureFfi: HandleAlloc, -{ - as HandleAlloc>::get_arc(handle).ffi_cancel() -} - -/// Complete a Rust future -/// -/// Note: the actually extern "C" scaffolding functions can't be generic, so we generate one for -/// each supported FFI type. -/// -/// # Safety -/// -/// - The [Handle] must not previously have been passed to [rust_future_free] -/// - The `T` param must correctly correspond to the [rust_future_new] call. It must -/// be `>::ReturnType` -pub unsafe fn rust_future_complete( - handle: Handle, - out_status: &mut RustCallStatus, -) -> ReturnType -where - dyn RustFutureFfi: HandleAlloc, -{ - as HandleAlloc>::get_arc(handle).ffi_complete(out_status) -} - -/// Free a Rust future, dropping the strong reference and releasing all references held by the -/// future. -/// -/// # Safety -/// -/// The [Handle] must not previously have been passed to [rust_future_free] -pub unsafe fn rust_future_free(handle: Handle) -where - dyn RustFutureFfi: HandleAlloc, -{ - as HandleAlloc>::consume_handle(handle).ffi_free() -} - -// Derive HandleAlloc for dyn RustFutureFfi for all FFI return types -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi<*const std::ffi::c_void>); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi); -derive_ffi_traits!(impl HandleAlloc for dyn RustFutureFfi<()>); diff --git a/third_party/rust/uniffi_core/src/ffi/rustfuture/scheduler.rs b/third_party/rust/uniffi_core/src/ffi/rustfuture/scheduler.rs deleted file mode 100644 index 629ee0c1092b..000000000000 --- a/third_party/rust/uniffi_core/src/ffi/rustfuture/scheduler.rs +++ /dev/null @@ -1,96 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use std::mem; - -use super::{RustFutureContinuationCallback, RustFuturePoll}; - -/// Schedules a [crate::RustFuture] by managing the continuation data -/// -/// This struct manages the continuation callback and data that comes from the foreign side. It -/// is responsible for calling the continuation callback when the future is ready to be woken up. -/// -/// The basic guarantees are: -/// -/// * Each callback will be invoked exactly once, with its associated data. -/// * If `wake()` is called, the callback will be invoked to wake up the future -- either -/// immediately or the next time we get a callback. -/// * If `cancel()` is called, the same will happen and the schedule will stay in the cancelled -/// state, invoking any future callbacks as soon as they're stored. - -#[derive(Debug)] -pub(super) enum Scheduler { - /// No continuations set, neither wake() nor cancel() called. - Empty, - /// `wake()` was called when there was no continuation set. The next time `store` is called, - /// the continuation should be immediately invoked with `RustFuturePoll::MaybeReady` - Waked, - /// The future has been cancelled, any future `store` calls should immediately result in the - /// continuation being called with `RustFuturePoll::Ready`. - Cancelled, - /// Continuation set, the next time `wake()` is called is called, we should invoke it. - Set(RustFutureContinuationCallback, u64), -} - -impl Scheduler { - pub(super) fn new() -> Self { - Self::Empty - } - - /// Store new continuation data if we are in the `Empty` state. If we are in the `Waked` or - /// `Cancelled` state, call the continuation immediately with the data. - pub(super) fn store(&mut self, callback: RustFutureContinuationCallback, data: u64) { - match self { - Self::Empty => *self = Self::Set(callback, data), - Self::Set(old_callback, old_data) => { - log::error!( - "store: observed `Self::Set` state. Is poll() being called from multiple threads at once?" - ); - old_callback(*old_data, RustFuturePoll::Ready); - *self = Self::Set(callback, data); - } - Self::Waked => { - *self = Self::Empty; - callback(data, RustFuturePoll::MaybeReady); - } - Self::Cancelled => { - callback(data, RustFuturePoll::Ready); - } - } - } - - pub(super) fn wake(&mut self) { - match self { - // If we had a continuation set, then call it and transition to the `Empty` state. - Self::Set(callback, old_data) => { - let old_data = *old_data; - let callback = *callback; - *self = Self::Empty; - callback(old_data, RustFuturePoll::MaybeReady); - } - // If we were in the `Empty` state, then transition to `Waked`. The next time `store` - // is called, we will immediately call the continuation. - Self::Empty => *self = Self::Waked, - // This is a no-op if we were in the `Cancelled` or `Waked` state. - _ => (), - } - } - - pub(super) fn cancel(&mut self) { - if let Self::Set(callback, old_data) = mem::replace(self, Self::Cancelled) { - callback(old_data, RustFuturePoll::Ready); - } - } - - pub(super) fn is_cancelled(&self) -> bool { - matches!(self, Self::Cancelled) - } -} - -// The `*const ()` data pointer references an object on the foreign side. -// This object must be `Sync` in Rust terminology -- it must be safe for us to pass the pointer to the continuation callback from any thread. -// If the foreign side upholds their side of the contract, then `Scheduler` is Send + Sync. - -unsafe impl Send for Scheduler {} -unsafe impl Sync for Scheduler {} diff --git a/third_party/rust/uniffi_core/src/ffi/rustfuture/tests.rs b/third_party/rust/uniffi_core/src/ffi/rustfuture/tests.rs deleted file mode 100644 index 886ee27c7154..000000000000 --- a/third_party/rust/uniffi_core/src/ffi/rustfuture/tests.rs +++ /dev/null @@ -1,223 +0,0 @@ -use once_cell::sync::OnceCell; -use std::{ - future::Future, - panic, - pin::Pin, - sync::{Arc, Mutex}, - task::{Context, Poll, Waker}, -}; - -use super::*; -use crate::{test_util::TestError, Lift, RustBuffer, RustCallStatusCode}; - -// Sender/Receiver pair that we use for testing -struct Channel { - result: Option>, - waker: Option, -} - -struct Sender(Arc>); - -impl Sender { - fn wake(&self) { - let inner = self.0.lock().unwrap(); - if let Some(waker) = &inner.waker { - waker.wake_by_ref(); - } - } - - fn send(&self, value: Result) { - let mut inner = self.0.lock().unwrap(); - if inner.result.replace(value).is_some() { - panic!("value already sent"); - } - if let Some(waker) = &inner.waker { - waker.wake_by_ref(); - } - } -} - -struct Receiver(Arc>); - -impl Future for Receiver { - type Output = Result; - - fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll> { - let mut inner = self.0.lock().unwrap(); - match &inner.result { - Some(v) => Poll::Ready(v.clone()), - None => { - inner.waker = Some(context.waker().clone()); - Poll::Pending - } - } - } -} - -// Create a sender and rust future that we can use for testing -fn channel() -> (Sender, Arc>) { - let channel = Arc::new(Mutex::new(Channel { - result: None, - waker: None, - })); - let rust_future = RustFuture::new(Receiver(channel.clone()), crate::UniFfiTag); - (Sender(channel), rust_future) -} - -/// Poll a Rust future and get an OnceCell that's set when the continuation is called -fn poll(rust_future: &Arc>) -> Arc> { - let cell = Arc::new(OnceCell::new()); - let handle = Arc::into_raw(cell.clone()) as u64; - rust_future.clone().ffi_poll(poll_continuation, handle); - cell -} - -extern "C" fn poll_continuation(data: u64, code: RustFuturePoll) { - let cell = unsafe { Arc::from_raw(data as *const OnceCell) }; - cell.set(code).expect("Error setting OnceCell"); -} - -fn complete(rust_future: Arc>) -> (RustBuffer, RustCallStatus) { - let mut out_status_code = RustCallStatus::default(); - let return_value = rust_future.ffi_complete(&mut out_status_code); - (return_value, out_status_code) -} - -#[test] -fn test_success() { - let (sender, rust_future) = channel(); - - // Test polling the rust future before it's ready - let continuation_result = poll(&rust_future); - assert_eq!(continuation_result.get(), None); - sender.wake(); - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::MaybeReady)); - - // Test polling the rust future when it's ready - let continuation_result = poll(&rust_future); - assert_eq!(continuation_result.get(), None); - sender.send(Ok("All done".into())); - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::MaybeReady)); - - // Future polls should immediately return ready - let continuation_result = poll(&rust_future); - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); - - // Complete the future - let (return_buf, call_status) = complete(rust_future); - assert_eq!(call_status.code, RustCallStatusCode::Success); - assert_eq!( - >::try_lift(return_buf).unwrap(), - "All done" - ); -} - -#[test] -fn test_error() { - let (sender, rust_future) = channel(); - - let continuation_result = poll(&rust_future); - assert_eq!(continuation_result.get(), None); - sender.send(Err("Something went wrong".into())); - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::MaybeReady)); - - let continuation_result = poll(&rust_future); - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); - - let (_, call_status) = complete(rust_future); - assert_eq!(call_status.code, RustCallStatusCode::Error); - unsafe { - assert_eq!( - >::try_lift_from_rust_buffer( - call_status.error_buf.assume_init() - ) - .unwrap(), - TestError::from("Something went wrong"), - ) - } -} - -// Once `complete` is called, the inner future should be released, even if wakers still hold a -// reference to the RustFuture -#[test] -fn test_cancel() { - let (_sender, rust_future) = channel(); - - let continuation_result = poll(&rust_future); - assert_eq!(continuation_result.get(), None); - rust_future.ffi_cancel(); - // Cancellation should immediately invoke the callback with RustFuturePoll::Ready - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); - - // Future polls should immediately invoke the callback with RustFuturePoll::Ready - let continuation_result = poll(&rust_future); - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); - - let (_, call_status) = complete(rust_future); - assert_eq!(call_status.code, RustCallStatusCode::Cancelled); -} - -// Once `free` is called, the inner future should be released, even if wakers still hold a -// reference to the RustFuture -#[test] -fn test_release_future() { - let (sender, rust_future) = channel(); - // Create a weak reference to the channel to use to check if rust_future has dropped its - // future. - let channel_weak = Arc::downgrade(&sender.0); - drop(sender); - // Create an extra ref to rust_future, simulating a waker that still holds a reference to - // it - let rust_future2 = rust_future.clone(); - - // Complete the rust future - rust_future.ffi_free(); - // Even though rust_future is still alive, the channel shouldn't be - assert!(Arc::strong_count(&rust_future2) > 0); - assert_eq!(channel_weak.strong_count(), 0); - assert!(channel_weak.upgrade().is_none()); -} - -// If `free` is called with a continuation still stored, we should call it them then. -// -// This shouldn't happen in practice, but it seems like good defensive programming -#[test] -fn test_complete_with_stored_continuation() { - let (_sender, rust_future) = channel(); - - let continuation_result = poll(&rust_future); - rust_future.ffi_free(); - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); -} - -// Test what happens if we see a `wake()` call while we're polling the future. This can -// happen, for example, with futures that are handled by a tokio thread pool. We should -// schedule another poll of the future in this case. -#[test] -fn test_wake_during_poll() { - let mut first_time = true; - let future = std::future::poll_fn(move |ctx| { - if first_time { - first_time = false; - // Wake the future while we are in the middle of polling it - ctx.waker().clone().wake(); - Poll::Pending - } else { - // The second time we're polled, we're ready - Poll::Ready("All done".to_owned()) - } - }); - let rust_future: Arc> = RustFuture::new(future, crate::UniFfiTag); - let continuation_result = poll(&rust_future); - // The continuation function should called immediately - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::MaybeReady)); - // A second poll should finish the future - let continuation_result = poll(&rust_future); - assert_eq!(continuation_result.get(), Some(&RustFuturePoll::Ready)); - let (return_buf, call_status) = complete(rust_future); - assert_eq!(call_status.code, RustCallStatusCode::Success); - assert_eq!( - >::try_lift(return_buf).unwrap(), - "All done" - ); -} diff --git a/third_party/rust/uniffi_core/src/ffi_converter_impls.rs b/third_party/rust/uniffi_core/src/ffi_converter_impls.rs index aec093154ab8..af18f3873ba1 100644 --- a/third_party/rust/uniffi_core/src/ffi_converter_impls.rs +++ b/third_party/rust/uniffi_core/src/ffi_converter_impls.rs @@ -20,11 +20,11 @@ /// /// This crate needs to implement `FFIConverter` on `UniFfiTag` instances for all UniFFI /// consumer crates. To do this, it defines blanket impls like `impl FFIConverter for u8`. -/// "UT" means an arbitrary `UniFfiTag` type. +/// "UT" means an abitrary `UniFfiTag` type. use crate::{ check_remaining, derive_ffi_traits, ffi_converter_rust_buffer_lift_and_lower, metadata, - ConvertError, FfiConverter, Lift, LiftRef, LiftReturn, Lower, LowerReturn, MetadataBuffer, - Result, RustBuffer, UnexpectedUniFFICallbackError, + ConvertError, FfiConverter, ForeignExecutor, Lift, LiftReturn, Lower, LowerReturn, + MetadataBuffer, Result, RustBuffer, UnexpectedUniFFICallbackError, }; use anyhow::bail; use bytes::buf::{Buf, BufMut}; @@ -405,6 +405,47 @@ where .concat(V::TYPE_ID_META); } +/// FFI support for [ForeignExecutor] +/// +/// These are passed over the FFI as opaque pointer-sized types representing the foreign executor. +/// The foreign bindings may use an actual pointer to the executor object, or a usized integer +/// handle. +unsafe impl FfiConverter for ForeignExecutor { + type FfiType = crate::ForeignExecutorHandle; + + // Passing these back to the foreign bindings is currently not supported + fn lower(executor: Self) -> Self::FfiType { + executor.handle + } + + fn write(executor: Self, buf: &mut Vec) { + // Use native endian when writing these values, so they can be casted to pointer values + match std::mem::size_of::() { + // Use native endian when reading these values, so they can be casted to pointer values + 4 => buf.put_u32_ne(executor.handle.0 as u32), + 8 => buf.put_u64_ne(executor.handle.0 as u64), + n => panic!("Invalid usize width: {n}"), + }; + } + + fn try_lift(executor: Self::FfiType) -> Result { + Ok(ForeignExecutor::new(executor)) + } + + fn try_read(buf: &mut &[u8]) -> Result { + let usize_val = match std::mem::size_of::() { + // Use native endian when reading these values, so they can be casted to pointer values + 4 => buf.get_u32_ne() as usize, + 8 => buf.get_u64_ne() as usize, + n => panic!("Invalid usize width: {n}"), + }; + >::try_lift(crate::ForeignExecutorHandle(usize_val as *const ())) + } + + const TYPE_ID_META: MetadataBuffer = + MetadataBuffer::from_code(metadata::codes::TYPE_FOREIGN_EXECUTOR); +} + derive_ffi_traits!(blanket u8); derive_ffi_traits!(blanket i8); derive_ffi_traits!(blanket u16); @@ -419,6 +460,7 @@ derive_ffi_traits!(blanket bool); derive_ffi_traits!(blanket String); derive_ffi_traits!(blanket Duration); derive_ffi_traits!(blanket SystemTime); +derive_ffi_traits!(blanket ForeignExecutor); // For composite types, derive LowerReturn, LiftReturn, etc, from Lift/Lower. // @@ -456,11 +498,7 @@ unsafe impl LowerReturn for () { } unsafe impl LiftReturn for () { - type ReturnType = (); - - fn try_lift_successful_return(_: ()) -> Result { - Ok(()) - } + fn lift_callback_return(_buf: RustBuffer) -> Self {} const TYPE_ID_META: MetadataBuffer = MetadataBuffer::from_code(metadata::codes::TYPE_UNIT); } @@ -497,15 +535,13 @@ where unsafe impl LiftReturn for Result where R: LiftReturn, - E: Lift + ConvertError, + E: Lift + ConvertError, { - type ReturnType = R::ReturnType; - - fn try_lift_successful_return(v: R::ReturnType) -> Result { - R::try_lift_successful_return(v).map(Ok) + fn lift_callback_return(buf: RustBuffer) -> Self { + Ok(R::lift_callback_return(buf)) } - fn lift_error(buf: RustBuffer) -> Self { + fn lift_callback_error(buf: RustBuffer) -> Self { match E::try_lift_from_rust_buffer(buf) { Ok(lifted_error) => Err(lifted_error), Err(anyhow_error) => { @@ -524,14 +560,3 @@ where .concat(R::TYPE_ID_META) .concat(E::TYPE_ID_META); } - -unsafe impl LiftRef for [T] -where - T: Lift, -{ - type LiftType = Vec; -} - -unsafe impl LiftRef for str { - type LiftType = String; -} diff --git a/third_party/rust/uniffi_core/src/ffi_converter_traits.rs b/third_party/rust/uniffi_core/src/ffi_converter_traits.rs index 4e7b9e06fa80..3b5914e32f41 100644 --- a/third_party/rust/uniffi_core/src/ffi_converter_traits.rs +++ b/third_party/rust/uniffi_core/src/ffi_converter_traits.rs @@ -51,10 +51,7 @@ use std::{borrow::Borrow, sync::Arc}; use anyhow::bail; use bytes::Buf; -use crate::{ - FfiDefault, Handle, MetadataBuffer, Result, RustBuffer, RustCallStatus, RustCallStatusCode, - UnexpectedUniFFICallbackError, -}; +use crate::{FfiDefault, MetadataBuffer, Result, RustBuffer, UnexpectedUniFFICallbackError}; /// Generalized FFI conversions /// @@ -305,41 +302,14 @@ pub unsafe trait LowerReturn: Sized { /// These traits should not be used directly, only in generated code, and the generated code should /// have fixture tests to test that everything works correctly together. pub unsafe trait LiftReturn: Sized { - /// FFI return type for trait interfaces - type ReturnType; - - /// Lift a successfully returned value from a trait interface - fn try_lift_successful_return(v: Self::ReturnType) -> Result; - - /// Lift a foreign returned value from a trait interface - /// - /// When we call a foreign-implemented trait interface method, we pass a &mut RustCallStatus - /// and get [Self::ReturnType] returned. This method takes both of those and lifts `Self` from - /// it. - fn lift_foreign_return(ffi_return: Self::ReturnType, call_status: RustCallStatus) -> Self { - match call_status.code { - RustCallStatusCode::Success => Self::try_lift_successful_return(ffi_return) - .unwrap_or_else(|e| { - Self::handle_callback_unexpected_error(UnexpectedUniFFICallbackError::new(e)) - }), - RustCallStatusCode::Error => { - Self::lift_error(unsafe { call_status.error_buf.assume_init() }) - } - _ => { - let e = >::try_lift(unsafe { - call_status.error_buf.assume_init() - }) - .unwrap_or_else(|e| format!("(Error lifting message: {e}")); - Self::handle_callback_unexpected_error(UnexpectedUniFFICallbackError::new(e)) - } - } - } + /// Lift a Rust value for a callback interface method result + fn lift_callback_return(buf: RustBuffer) -> Self; /// Lift a Rust value for a callback interface method error result /// /// This is called for "expected errors" -- the callback method returns a Result<> type and the /// foreign code throws an exception that corresponds to the error type. - fn lift_error(_buf: RustBuffer) -> Self { + fn lift_callback_error(_buf: RustBuffer) -> Self { panic!("Callback interface method returned unexpected error") } @@ -381,66 +351,6 @@ pub trait ConvertError: Sized { fn try_convert_unexpected_callback_error(e: UnexpectedUniFFICallbackError) -> Result; } -/// Manage handles for `Arc` instances -/// -/// Handles are used to manage objects that are passed across the FFI. They general usage is: -/// -/// * Rust creates an `Arc<>` -/// * Rust uses `new_handle` to create a handle that represents the Arc reference -/// * Rust passes the handle to the foreign code as a `u64` -/// * The foreign code passes the handle back to `Rust` to refer to the object: -/// * Handle are usually passed as borrowed values. When an FFI function inputs a handle as an -/// argument, the foreign code simply passes a copy of the `u64` to Rust, which calls `get_arc` -/// to get a new `Arc<>` clone for it. -/// * Handles are returned as owned values. When an FFI function returns a handle, the foreign -/// code either stops using the handle after returning it or calls `clone_handle` and returns -/// the clone. -/// * Eventually the foreign code may destroy their handle by passing it into a "free" FFI -/// function. This functions input an owned handle and consume it. -/// -/// The foreign code also defines their own handles. These represent foreign objects that are -/// passed to Rust. Using foreign handles is essentially the same as above, but in reverse. -/// -/// Handles must always be `Send` and the objects they reference must always be `Sync`. -/// This means that it must be safe to send handles to other threads and use them there. -/// -/// Note: this only needs to be derived for unsized types, there's a blanket impl for `T: Sized`. -/// -/// ## Safety -/// -/// All traits are unsafe (implementing it requires `unsafe impl`) because we can't guarantee -/// that it's safe to pass your type out to foreign-language code and back again. Buggy -/// implementations of this trait might violate some assumptions made by the generated code, -/// or might not match with the corresponding code in the generated foreign-language bindings. -/// These traits should not be used directly, only in generated code, and the generated code should -/// have fixture tests to test that everything works correctly together. -/// `&T` using the Arc. -pub unsafe trait HandleAlloc: Send + Sync { - /// Create a new handle for an Arc value - /// - /// Use this to lower an Arc into a handle value before passing it across the FFI. - /// The newly-created handle will have reference count = 1. - fn new_handle(value: Arc) -> Handle; - - /// Clone a handle - /// - /// This creates a new handle from an existing one. - /// It's used when the foreign code wants to pass back an owned handle and still keep a copy - /// for themselves. - fn clone_handle(handle: Handle) -> Handle; - - /// Get a clone of the `Arc<>` using a "borrowed" handle. - /// - /// Take care that the handle can not be destroyed between when it's passed and when - /// `get_arc()` is called. #1797 is a cautionary tale. - fn get_arc(handle: Handle) -> Arc { - Self::consume_handle(Self::clone_handle(handle)) - } - - /// Consume a handle, getting back the initial `Arc<>` - fn consume_handle(handle: Handle) -> Arc; -} - /// Derive FFI traits /// /// This can be used to derive: @@ -529,10 +439,9 @@ macro_rules! derive_ffi_traits { (impl $(<$($generic:ident),*>)? $(::uniffi::)? LiftReturn<$ut:path> for $ty:ty $(where $($where:tt)*)?) => { unsafe impl $(<$($generic),*>)* $crate::LiftReturn<$ut> for $ty $(where $($where)*)* { - type ReturnType = >::FfiType; - - fn try_lift_successful_return(v: Self::ReturnType) -> $crate::Result { - >::try_lift(v) + fn lift_callback_return(buf: $crate::RustBuffer) -> Self { + >::try_lift_from_rust_buffer(buf) + .expect("Error reading callback interface result") } const TYPE_ID_META: $crate::MetadataBuffer = >::TYPE_ID_META; @@ -554,50 +463,4 @@ macro_rules! derive_ffi_traits { } } }; - - (impl $(<$($generic:ident),*>)? $(::uniffi::)? HandleAlloc<$ut:path> for $ty:ty $(where $($where:tt)*)?) => { - // Derived HandleAlloc implementation. - // - // This is only needed for !Sized types like `dyn Trait`, below is a blanket implementation - // for any sized type. - unsafe impl $(<$($generic),*>)* $crate::HandleAlloc<$ut> for $ty $(where $($where)*)* - { - // To implement HandleAlloc for an unsized type, wrap it with a second Arc which - // converts the wide pointer into a normal pointer. - - fn new_handle(value: ::std::sync::Arc) -> $crate::Handle { - $crate::Handle::from_pointer(::std::sync::Arc::into_raw(::std::sync::Arc::new(value))) - } - - fn clone_handle(handle: $crate::Handle) -> $crate::Handle { - unsafe { - ::std::sync::Arc::<::std::sync::Arc>::increment_strong_count(handle.as_pointer::<::std::sync::Arc>()); - } - handle - } - - fn consume_handle(handle: $crate::Handle) -> ::std::sync::Arc { - unsafe { - ::std::sync::Arc::::clone( - &std::sync::Arc::<::std::sync::Arc::>::from_raw(handle.as_pointer::<::std::sync::Arc>()) - ) - } - } - } - }; -} - -unsafe impl HandleAlloc for T { - fn new_handle(value: Arc) -> Handle { - Handle::from_pointer(Arc::into_raw(value)) - } - - fn clone_handle(handle: Handle) -> Handle { - unsafe { Arc::increment_strong_count(handle.as_pointer::()) }; - handle - } - - fn consume_handle(handle: Handle) -> Arc { - unsafe { Arc::from_raw(handle.as_pointer()) } - } } diff --git a/third_party/rust/uniffi_core/src/lib.rs b/third_party/rust/uniffi_core/src/lib.rs index 1f3a2403f826..c84b403dced1 100644 --- a/third_party/rust/uniffi_core/src/lib.rs +++ b/third_party/rust/uniffi_core/src/lib.rs @@ -45,8 +45,7 @@ pub mod metadata; pub use ffi::*; pub use ffi_converter_traits::{ - ConvertError, FfiConverter, FfiConverterArc, HandleAlloc, Lift, LiftRef, LiftReturn, Lower, - LowerReturn, + ConvertError, FfiConverter, FfiConverterArc, Lift, LiftRef, LiftReturn, Lower, LowerReturn, }; pub use metadata::*; @@ -58,8 +57,9 @@ pub mod deps { pub use async_compat; pub use bytes; pub use log; - pub use oneshot; pub use static_assertions; + // Export this dependency for the 0.25 branch so that we can use it in `setup_scaffolding.rs` + pub use once_cell; } mod panichook; diff --git a/third_party/rust/uniffi_core/src/metadata.rs b/third_party/rust/uniffi_core/src/metadata.rs index dc61a1bfcbc7..770d2b36d5e0 100644 --- a/third_party/rust/uniffi_core/src/metadata.rs +++ b/third_party/rust/uniffi_core/src/metadata.rs @@ -32,14 +32,13 @@ pub mod codes { pub const RECORD: u8 = 2; pub const ENUM: u8 = 3; pub const INTERFACE: u8 = 4; + pub const ERROR: u8 = 5; pub const NAMESPACE: u8 = 6; pub const CONSTRUCTOR: u8 = 7; pub const UDL_FILE: u8 = 8; pub const CALLBACK_INTERFACE: u8 = 9; pub const TRAIT_METHOD: u8 = 10; pub const UNIFFI_TRAIT: u8 = 11; - pub const TRAIT_INTERFACE: u8 = 12; - pub const CALLBACK_TRAIT_INTERFACE: u8 = 13; pub const UNKNOWN: u8 = 255; // Type codes @@ -67,24 +66,20 @@ pub mod codes { pub const TYPE_CALLBACK_INTERFACE: u8 = 21; pub const TYPE_CUSTOM: u8 = 22; pub const TYPE_RESULT: u8 = 23; - pub const TYPE_TRAIT_INTERFACE: u8 = 24; - pub const TYPE_CALLBACK_TRAIT_INTERFACE: u8 = 25; + pub const TYPE_FUTURE: u8 = 24; + pub const TYPE_FOREIGN_EXECUTOR: u8 = 25; pub const TYPE_UNIT: u8 = 255; - // Literal codes for LiteralMetadata + // Literal codes for LiteralMetadata - note that we don't support + // all variants in the "emit/reader" context. pub const LIT_STR: u8 = 0; pub const LIT_INT: u8 = 1; pub const LIT_FLOAT: u8 = 2; pub const LIT_BOOL: u8 = 3; - pub const LIT_NONE: u8 = 4; - pub const LIT_SOME: u8 = 5; - pub const LIT_EMPTY_SEQ: u8 = 6; + pub const LIT_NULL: u8 = 4; } -// For large errors (e.g. enums) a buffer size of ~4k - ~8k -// is not enough. See issues on Github: #1968 and #2041 and -// for an example see fixture/large-error -const BUF_SIZE: usize = 16384; +const BUF_SIZE: usize = 4096; // This struct is a kludge around the fact that Rust const generic support doesn't quite handle our // needs. @@ -173,17 +168,7 @@ impl MetadataBuffer { self.concat_value(value as u8) } - // Option - pub const fn concat_option_bool(self, value: Option) -> Self { - self.concat_value(match value { - None => 0, - Some(false) => 1, - Some(true) => 2, - }) - } - - // Concatenate a string to this buffer. The maximum string length is 255 bytes. For longer strings, - // use `concat_long_str()`. + // Concatenate a string to this buffer. // // Strings are encoded as a `u8` length, followed by the utf8 data. // @@ -204,28 +189,6 @@ impl MetadataBuffer { self } - // Concatenate a longer string to this buffer. - // - // Strings are encoded as a `u16` length, followed by the utf8 data. - // - // This consumes self, which is convenient for the proc-macro code and also allows us to avoid - // allocated an extra buffer. - pub const fn concat_long_str(mut self, string: &str) -> Self { - assert!(self.size + string.len() + 1 < BUF_SIZE); - let [lo, hi] = (string.len() as u16).to_le_bytes(); - self.bytes[self.size] = lo; - self.bytes[self.size + 1] = hi; - self.size += 2; - let bytes = string.as_bytes(); - let mut i = 0; - while i < bytes.len() { - self.bytes[self.size] = bytes[i]; - self.size += 1; - i += 1; - } - self - } - // Create an array from this MetadataBuffer // // SIZE should always be `self.size`. This is part of the kludge to hold us over until Rust diff --git a/third_party/rust/uniffi_macros/.cargo-checksum.json b/third_party/rust/uniffi_macros/.cargo-checksum.json dissimilarity index 100% index 9db049289cc0..96e44ac74eca 100644 --- a/third_party/rust/uniffi_macros/.cargo-checksum.json +++ b/third_party/rust/uniffi_macros/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"a292239ca3c72852768fdf0e7bc2dd6386af7bf1ab0ef56dff01e1c9e781b2ca","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/custom.rs":"36cd6c2eeb8efdc34e59dff634a22e79471ab17f49ceb0f131da5f144313f7e4","src/default.rs":"77466ac54da69094bcdccc5927d0980b1e9dd0095647ca825830673c48847a53","src/enum_.rs":"afe0a6534d8e7f68047e3f1afad9369d5d5650f4c7555e8d4173f24126c715ba","src/error.rs":"30168378da9a23e6530ffe68647bf6618d07a0aaa236d5009137a922798a0e88","src/export.rs":"42c5e784c1dccc796c8b6ea29c2dc1811e48a531488a3ed0e2a59330778a7e41","src/export/attributes.rs":"c848f8c309c4cf7a168f038834752dc4816b5c853768d7c331ea4cd5ce0841b7","src/export/callback_interface.rs":"794b0665dc7eb02ea854c61c8bb2781e0b4ac1de646d95a8fd7791f770f2e6e3","src/export/item.rs":"4e86875692c2d2993fde12e78dbde2cbffa5675ede143577d5620126401efe05","src/export/scaffolding.rs":"b25167d2213b6d6c5ba653622f26791e8c3e74a5ecce6512ec27009fc8bf68e4","src/export/trait_interface.rs":"f07f9908ee28661de4586d89b693f3d93dae5e5cba8a089eff25f20bbf6b373b","src/export/utrait.rs":"b55533d3eef8262944d3c0d9a3a9cba0615d2d5af8608f0919abc7699989e2a8","src/fnsig.rs":"5e434a1cc87166c5245424bb14e896eb766bf680d4d50d4b8536852f91487d7c","src/lib.rs":"a28bbfd2d1dc835306ff6072f75761bb6b3a158477bba966057776c527fe6d70","src/object.rs":"5419ed64c8120aef811a77c2205f58a7a537bdf34ae04f9c92dd3aaa176eed39","src/record.rs":"29072542cc2f3e027bd7c59b45ba913458f8213d1b2b33bc70d140baa98fcdc8","src/setup_scaffolding.rs":"173fdc916967d54bd6532def16d12e5bb85467813a46a031d3338b77625756bb","src/test.rs":"1673f282bb35d6b0740ad0e5f11826c2852d7a0db29604c2258f457415b537e8","src/util.rs":"a2c3693343e78dffb2a7f7b39eeb9b7f298b66688f1766a7c08113cf9431ef4c"},"package":"18331d35003f46f0d04047fbe4227291815b83a937a8c32bc057f990962182c4"} \ No newline at end of file +{"files":{"Cargo.toml":"376811e12479a0cced9375a12a2e3186da053b3c7520374bf6f2b54d23282082","src/custom.rs":"36cd6c2eeb8efdc34e59dff634a22e79471ab17f49ceb0f131da5f144313f7e4","src/enum_.rs":"2d3181ef22468deb4e8f48b7b1ed9421134604c2c226d5084c453ebb2cedbfd5","src/error.rs":"0b5beb8a2c8c93c30c56f2f80538bf1f1c8e6a99b2b1c934ad12a4feb75a2fc0","src/export.rs":"6d05417f0b10a9d6df9e96a6ed771c89a5e59e6e52d1ce812025bfe68e9f717e","src/export/attributes.rs":"53a27264882ab0a802a0ee109a2ea3f3456d4c83c85eaa5c0f5912d4486ab843","src/export/callback_interface.rs":"ad2782b7ca930dc067c391394480362be1fbf331d8786be089c0a87415c85a88","src/export/item.rs":"a7b74e6400ec6c5e8fb09d8842ce718b9555d75de13fdf5fecbab2fceeec7cbf","src/export/scaffolding.rs":"8ab2b9b0c5ad5b5477963843b7a58d496344da7de1a2a4b07f30f22275c8f3c9","src/export/utrait.rs":"ce4a3d629aaf0b44b8c5ce6794c5d5b0d7f86f46f0dd6b6ecb134514be330f0d","src/fnsig.rs":"886ceec806b429c7d86fe00d0d84f7b04e21142605f7a61d182f9f616210cd2b","src/lib.rs":"501c736647eff2705c5565f80e554d2e440cceceed95044c9fe147fc309afb48","src/object.rs":"0a14d6b8ccb4faef93a1f61a97ac7d47a80b6581383f4a6e0a4789f53e66e630","src/record.rs":"fbff287bb2d0b7a9eb35ef3161fbd1abbc21f3aa08e88bd4242dd12acbfa3ee9","src/setup_scaffolding.rs":"60b48a56fae16cf01824586b90e6440da3362135d98fc07aaed624c57f806163","src/test.rs":"1673f282bb35d6b0740ad0e5f11826c2852d7a0db29604c2258f457415b537e8","src/util.rs":"217ecef0e4dabd158a7597aa3d00d94477993a90b388afbbc0fb39e14f6b013e"},"package":"11cf7a58f101fcedafa5b77ea037999b88748607f0ef3a33eaa0efc5392e92e4"} \ No newline at end of file diff --git a/third_party/rust/uniffi_macros/Cargo.toml b/third_party/rust/uniffi_macros/Cargo.toml index 5ae193e39273..9d3908ae8dad 100644 --- a/third_party/rust/uniffi_macros/Cargo.toml +++ b/third_party/rust/uniffi_macros/Cargo.toml @@ -12,12 +12,11 @@ [package] edition = "2021" name = "uniffi_macros" -version = "0.27.1" +version = "0.25.3" authors = ["Firefox Sync Team "] description = "a multi-language bindings generator for rust (convenience macros)" homepage = "https://mozilla.github.io/uniffi-rs" documentation = "https://mozilla.github.io/uniffi-rs" -readme = "README.md" keywords = [ "ffi", "bindgen", @@ -48,7 +47,6 @@ version = "1.0" [dependencies.serde] version = "1.0.136" -features = ["derive"] [dependencies.syn] version = "2.0" @@ -61,13 +59,11 @@ features = [ version = "0.5.9" [dependencies.uniffi_build] -version = "=0.27.1" -optional = true +version = "=0.25.3" [dependencies.uniffi_meta] -version = "=0.27.1" +version = "=0.25.3" [features] default = [] nightly = [] -trybuild = ["dep:uniffi_build"] diff --git a/third_party/rust/uniffi_macros/README.md b/third_party/rust/uniffi_macros/README.md deleted file mode 100644 index 64ac3486a3bf..000000000000 --- a/third_party/rust/uniffi_macros/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# UniFFI - a multi-language bindings generator for Rust - -UniFFI is a toolkit for building cross-platform software components in Rust. - -For the impatient, see [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/) -or [**the UniFFI examples**](https://github.com/mozilla/uniffi-rs/tree/main/examples#example-uniffi-components). - -By writing your core business logic in Rust and describing its interface in an "object model", -you can use UniFFI to help you: - -* Compile your Rust code into a shared library for use on different target platforms. -* Generate bindings to load and use the library from different target languages. - -You can describe your object model in an [interface definition file](https://mozilla.github.io/uniffi-rs/udl_file_spec.html) -or [by using proc-macros](https://mozilla.github.io/uniffi-rs/proc_macro/index.html). - -UniFFI is currently used extensively by Mozilla in Firefox mobile and desktop browsers; -written once in Rust, auto-generated bindings allow that functionality to be called -from both Kotlin (for Android apps) and Swift (for iOS apps). -It also has a growing community of users shipping various cool things to many users. - -UniFFI comes with support for **Kotlin**, **Swift**, **Python** and **Ruby** with 3rd party bindings available for **C#** and **Golang**. -Additional foreign language bindings can be developed externally and we welcome contributions to list them here. -See [Third-party foreign language bindings](#third-party-foreign-language-bindings). - -## User Guide - -You can read more about using the tool in [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/). - -We consider it ready for production use, but UniFFI is a long way from a 1.0 release with lots of internal work still going on. -We try hard to avoid breaking simple consumers, but more advanced things might break as you upgrade over time. - -### Etymology and Pronunciation - -ˈjuːnɪfaɪ. Pronounced to rhyme with "unify". - -A portmanteau word that also puns with "unify", to signify the joining of one codebase accessed from many languages. - -uni - [Latin ūni-, from ūnus, one] -FFI - [Abbreviation, Foreign Function Interface] - -## Alternative tools - -Other tools we know of which try and solve a similarly shaped problem are: - -* [Diplomat](https://github.com/rust-diplomat/diplomat/) - see our [writeup of - the different approach taken by that tool](docs/diplomat-and-macros.md) -* [Interoptopus](https://github.com/ralfbiedert/interoptopus/) - -(Please open a PR if you think other tools should be listed!) - -## Third-party foreign language bindings - -* [Kotlin Multiplatform support](https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings). The repository contains Kotlin Multiplatform bindings generation for UniFFI, letting you target both JVM and Native. -* [Go bindings](https://github.com/NordSecurity/uniffi-bindgen-go) -* [C# bindings](https://github.com/NordSecurity/uniffi-bindgen-cs) -* [Dart bindings](https://github.com/NiallBunting/uniffi-rs-dart) - -### External resources - -There are a few third-party resources that make it easier to work with UniFFI: - -* [Plugin support for `.udl` files](https://github.com/Lonami/uniffi-dl) for the IDEA platform ([*uniffi-dl* in the JetBrains marketplace](https://plugins.jetbrains.com/plugin/20527-uniffi-dl)). It provides syntax highlighting, code folding, code completion, reference resolution and navigation (among others features) for the [UniFFI Definition Language (UDL)](https://mozilla.github.io/uniffi-rs/). -* [cargo swift](https://github.com/antoniusnaumann/cargo-swift), a cargo plugin to build a Swift Package from Rust code. It provides an init command for setting up a UniFFI crate and a package command for building a Swift package from Rust code - without the need for additional configuration or build scripts. -* [Cargo NDK Gradle Plugin](https://github.com/willir/cargo-ndk-android-gradle) allows you to build Rust code using [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk), which generally makes Android library builds less painful. -* [`uniffi-starter`](https://github.com/ianthetechie/uniffi-starter) is a minimal project demonstrates a wide range of UniFFI in a complete project in a compact manner. It includes a full Android library build process, an XCFramework generation script, and example Swift package structure. - -(Please open a PR if you think other resources should be listed!) - -## Contributing - -If this tool sounds interesting to you, please help us develop it! You can: - -* View the [contributor guidelines](./docs/contributing.md). -* File or work on [issues](https://github.com/mozilla/uniffi-rs/issues) here in GitHub. -* Join discussions in the [#uniffi:mozilla.org](https://matrix.to/#/#uniffi:mozilla.org) - room on Matrix. - -## Code of Conduct - -This project is governed by Mozilla's [Community Participation Guidelines](./CODE_OF_CONDUCT.md). diff --git a/third_party/rust/uniffi_macros/src/default.rs b/third_party/rust/uniffi_macros/src/default.rs deleted file mode 100644 index 000c20584579..000000000000 --- a/third_party/rust/uniffi_macros/src/default.rs +++ /dev/null @@ -1,133 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use crate::util::kw; -use proc_macro2::TokenStream; -use quote::{quote, ToTokens}; -use syn::{ - bracketed, parenthesized, - parse::{Nothing, Parse, ParseStream}, - token::{Bracket, Paren}, - Lit, -}; - -/// Default value -#[derive(Clone)] -pub enum DefaultValue { - Literal(Lit), - None(kw::None), - Some { - some: kw::Some, - paren: Paren, - inner: Box, - }, - EmptySeq(Bracket), -} - -impl ToTokens for DefaultValue { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - DefaultValue::Literal(lit) => lit.to_tokens(tokens), - DefaultValue::None(kw) => kw.to_tokens(tokens), - DefaultValue::Some { inner, .. } => tokens.extend(quote! { Some(#inner) }), - DefaultValue::EmptySeq(_) => tokens.extend(quote! { [] }), - } - } -} - -impl Parse for DefaultValue { - fn parse(input: ParseStream<'_>) -> syn::Result { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::None) { - let none_kw: kw::None = input.parse()?; - Ok(Self::None(none_kw)) - } else if lookahead.peek(kw::Some) { - let some: kw::Some = input.parse()?; - let content; - let paren = parenthesized!(content in input); - Ok(Self::Some { - some, - paren, - inner: content.parse()?, - }) - } else if lookahead.peek(Bracket) { - let content; - let bracket = bracketed!(content in input); - content.parse::()?; - Ok(Self::EmptySeq(bracket)) - } else { - Ok(Self::Literal(input.parse()?)) - } - } -} - -impl DefaultValue { - fn metadata_calls(&self) -> syn::Result { - match self { - DefaultValue::Literal(Lit::Int(i)) if !i.suffix().is_empty() => Err( - syn::Error::new_spanned(i, "integer literals with suffix not supported here"), - ), - DefaultValue::Literal(Lit::Float(f)) if !f.suffix().is_empty() => Err( - syn::Error::new_spanned(f, "float literals with suffix not supported here"), - ), - - DefaultValue::Literal(Lit::Str(s)) => Ok(quote! { - .concat_value(::uniffi::metadata::codes::LIT_STR) - .concat_str(#s) - }), - DefaultValue::Literal(Lit::Int(i)) => { - let digits = i.base10_digits(); - Ok(quote! { - .concat_value(::uniffi::metadata::codes::LIT_INT) - .concat_str(#digits) - }) - } - DefaultValue::Literal(Lit::Float(f)) => { - let digits = f.base10_digits(); - Ok(quote! { - .concat_value(::uniffi::metadata::codes::LIT_FLOAT) - .concat_str(#digits) - }) - } - DefaultValue::Literal(Lit::Bool(b)) => Ok(quote! { - .concat_value(::uniffi::metadata::codes::LIT_BOOL) - .concat_bool(#b) - }), - - DefaultValue::Literal(_) => Err(syn::Error::new_spanned( - self, - "this type of literal is not currently supported as a default", - )), - - DefaultValue::EmptySeq(_) => Ok(quote! { - .concat_value(::uniffi::metadata::codes::LIT_EMPTY_SEQ) - }), - - DefaultValue::None(_) => Ok(quote! { - .concat_value(::uniffi::metadata::codes::LIT_NONE) - }), - - DefaultValue::Some { inner, .. } => { - let inner_calls = inner.metadata_calls()?; - Ok(quote! { - .concat_value(::uniffi::metadata::codes::LIT_SOME) - #inner_calls - }) - } - } - } -} - -pub fn default_value_metadata_calls(default: &Option) -> syn::Result { - Ok(match default { - Some(default) => { - let metadata_calls = default.metadata_calls()?; - quote! { - .concat_bool(true) - #metadata_calls - } - } - None => quote! { .concat_bool(false) }, - }) -} diff --git a/third_party/rust/uniffi_macros/src/enum_.rs b/third_party/rust/uniffi_macros/src/enum_.rs dissimilarity index 69% index fd98da31299b..32abfa08ccb7 100644 --- a/third_party/rust/uniffi_macros/src/enum_.rs +++ b/third_party/rust/uniffi_macros/src/enum_.rs @@ -1,371 +1,195 @@ -use proc_macro2::{Ident, Span, TokenStream}; -use quote::quote; -use syn::{ - parse::{Parse, ParseStream}, - spanned::Spanned, - Attribute, Data, DataEnum, DeriveInput, Expr, Index, Lit, Variant, -}; - -use crate::util::{ - create_metadata_items, derive_all_ffi_traits, either_attribute_arg, extract_docstring, - ident_to_string, kw, mod_path, parse_comma_separated, tagged_impl_header, - try_metadata_value_from_usize, try_read_field, AttributeSliceExt, UniffiAttributeArgs, -}; - -fn extract_repr(attrs: &[Attribute]) -> syn::Result> { - let mut result = None; - for attr in attrs { - if attr.path().is_ident("repr") { - attr.parse_nested_meta(|meta| { - result = match meta.path.get_ident() { - Some(i) => { - let s = i.to_string(); - match s.as_str() { - "u8" | "u16" | "u32" | "u64" | "usize" | "i8" | "i16" | "i32" - | "i64" | "isize" => Some(i.clone()), - // while the default repr for an enum is `isize` we don't apply that default here. - _ => None, - } - } - _ => None, - }; - Ok(()) - })? - } - } - Ok(result) -} - -pub fn expand_enum( - input: DeriveInput, - // Attributes from #[derive_error_for_udl()], if we are in udl mode - attr_from_udl_mode: Option, - udl_mode: bool, -) -> syn::Result { - let enum_ = match input.data { - Data::Enum(e) => e, - _ => { - return Err(syn::Error::new( - Span::call_site(), - "This derive must only be used on enums", - )) - } - }; - let ident = &input.ident; - let docstring = extract_docstring(&input.attrs)?; - let discr_type = extract_repr(&input.attrs)?; - let mut attr: EnumAttr = input.attrs.parse_uniffi_attr_args()?; - if let Some(attr_from_udl_mode) = attr_from_udl_mode { - attr = attr.merge(attr_from_udl_mode)?; - } - let ffi_converter_impl = enum_ffi_converter_impl(ident, &enum_, udl_mode, &attr); - - let meta_static_var = (!udl_mode).then(|| { - enum_meta_static_var(ident, docstring, discr_type, &enum_, &attr) - .unwrap_or_else(syn::Error::into_compile_error) - }); - - Ok(quote! { - #ffi_converter_impl - #meta_static_var - }) -} - -pub(crate) fn enum_ffi_converter_impl( - ident: &Ident, - enum_: &DataEnum, - udl_mode: bool, - attr: &EnumAttr, -) -> TokenStream { - enum_or_error_ffi_converter_impl( - ident, - enum_, - udl_mode, - attr, - quote! { ::uniffi::metadata::codes::TYPE_ENUM }, - ) -} - -pub(crate) fn rich_error_ffi_converter_impl( - ident: &Ident, - enum_: &DataEnum, - udl_mode: bool, - attr: &EnumAttr, -) -> TokenStream { - enum_or_error_ffi_converter_impl( - ident, - enum_, - udl_mode, - attr, - quote! { ::uniffi::metadata::codes::TYPE_ENUM }, - ) -} - -fn enum_or_error_ffi_converter_impl( - ident: &Ident, - enum_: &DataEnum, - udl_mode: bool, - attr: &EnumAttr, - metadata_type_code: TokenStream, -) -> TokenStream { - let name = ident_to_string(ident); - let impl_spec = tagged_impl_header("FfiConverter", ident, udl_mode); - let derive_ffi_traits = derive_all_ffi_traits(ident, udl_mode); - let mod_path = match mod_path() { - Ok(p) => p, - Err(e) => return e.into_compile_error(), - }; - let mut write_match_arms: Vec<_> = enum_ - .variants - .iter() - .enumerate() - .map(|(i, v)| { - let v_ident = &v.ident; - let field_idents = v - .fields - .iter() - .enumerate() - .map(|(i, f)| { - f.ident - .clone() - .unwrap_or_else(|| Ident::new(&format!("e{i}"), f.span())) - }) - .collect::>(); - let idx = Index::from(i + 1); - let write_fields = - std::iter::zip(v.fields.iter(), field_idents.iter()).map(|(f, ident)| { - let ty = &f.ty; - quote! { - <#ty as ::uniffi::Lower>::write(#ident, buf); - } - }); - let is_tuple = v.fields.iter().any(|f| f.ident.is_none()); - let fields = if is_tuple { - quote! { ( #(#field_idents),* ) } - } else { - quote! { { #(#field_idents),* } } - }; - - quote! { - Self::#v_ident #fields => { - ::uniffi::deps::bytes::BufMut::put_i32(buf, #idx); - #(#write_fields)* - } - } - }) - .collect(); - if attr.non_exhaustive.is_some() { - write_match_arms.push(quote! { - _ => panic!("Unexpected variant in non-exhaustive enum"), - }) - } - let write_impl = quote! { - match obj { #(#write_match_arms)* } - }; - - let try_read_match_arms = enum_.variants.iter().enumerate().map(|(i, v)| { - let idx = Index::from(i + 1); - let v_ident = &v.ident; - let is_tuple = v.fields.iter().any(|f| f.ident.is_none()); - let try_read_fields = v.fields.iter().map(try_read_field); - - if is_tuple { - quote! { - #idx => Self::#v_ident ( #(#try_read_fields)* ), - } - } else { - quote! { - #idx => Self::#v_ident { #(#try_read_fields)* }, - } - } - }); - let error_format_string = format!("Invalid {ident} enum value: {{}}"); - let try_read_impl = quote! { - ::uniffi::check_remaining(buf, 4)?; - - Ok(match ::uniffi::deps::bytes::Buf::get_i32(buf) { - #(#try_read_match_arms)* - v => ::uniffi::deps::anyhow::bail!(#error_format_string, v), - }) - }; - - quote! { - #[automatically_derived] - unsafe #impl_spec { - ::uniffi::ffi_converter_rust_buffer_lift_and_lower!(crate::UniFfiTag); - - fn write(obj: Self, buf: &mut ::std::vec::Vec) { - #write_impl - } - - fn try_read(buf: &mut &[::std::primitive::u8]) -> ::uniffi::deps::anyhow::Result { - #try_read_impl - } - - const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(#metadata_type_code) - .concat_str(#mod_path) - .concat_str(#name); - } - - #derive_ffi_traits - } -} - -pub(crate) fn enum_meta_static_var( - ident: &Ident, - docstring: String, - discr_type: Option, - enum_: &DataEnum, - attr: &EnumAttr, -) -> syn::Result { - let name = ident_to_string(ident); - let module_path = mod_path()?; - let non_exhaustive = attr.non_exhaustive.is_some(); - - let mut metadata_expr = quote! { - ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::ENUM) - .concat_str(#module_path) - .concat_str(#name) - .concat_option_bool(None) // forced_flatness - }; - metadata_expr.extend(match discr_type { - None => quote! { .concat_bool(false) }, - Some(t) => quote! { .concat_bool(true).concat(<#t as ::uniffi::Lower>::TYPE_ID_META) } - }); - metadata_expr.extend(variant_metadata(enum_)?); - metadata_expr.extend(quote! { - .concat_bool(#non_exhaustive) - .concat_long_str(#docstring) - }); - Ok(create_metadata_items("enum", &name, metadata_expr, None)) -} - -fn variant_value(v: &Variant) -> syn::Result { - let Some((_, e)) = &v.discriminant else { - return Ok(quote! { .concat_bool(false) }); - }; - // Attempting to expose an enum value which we don't understand is a hard-error - // rather than silently ignoring it. If we had the ability to emit a warning that - // might make more sense. - - // We can't sanely handle most expressions other than literals, but we can handle - // negative literals. - let mut negate = false; - let lit = match e { - Expr::Lit(lit) => lit, - Expr::Unary(expr_unary) if matches!(expr_unary.op, syn::UnOp::Neg(_)) => { - negate = true; - match *expr_unary.expr { - Expr::Lit(ref lit) => lit, - _ => { - return Err(syn::Error::new_spanned( - e, - "UniFFI disciminant values must be a literal", - )); - } - } - } - _ => { - return Err(syn::Error::new_spanned( - e, - "UniFFI disciminant values must be a literal", - )); - } - }; - let Lit::Int(ref intlit) = lit.lit else { - return Err(syn::Error::new_spanned( - v, - "UniFFI disciminant values must be a literal integer", - )); - }; - if !intlit.suffix().is_empty() { - return Err(syn::Error::new_spanned( - intlit, - "integer literals with suffix not supported by UniFFI here", - )); - } - let digits = if negate { - format!("-{}", intlit.base10_digits()) - } else { - intlit.base10_digits().to_string() - }; - Ok(quote! { - .concat_bool(true) - .concat_value(::uniffi::metadata::codes::LIT_INT) - .concat_str(#digits) - }) -} - -pub fn variant_metadata(enum_: &DataEnum) -> syn::Result> { - let variants_len = - try_metadata_value_from_usize(enum_.variants.len(), "UniFFI limits enums to 256 variants")?; - std::iter::once(Ok(quote! { .concat_value(#variants_len) })) - .chain(enum_.variants.iter().map(|v| { - let fields_len = try_metadata_value_from_usize( - v.fields.len(), - "UniFFI limits enum variants to 256 fields", - )?; - - let field_names = v - .fields - .iter() - .map(|f| f.ident.as_ref().map(ident_to_string).unwrap_or_default()) - .collect::>(); - - let name = ident_to_string(&v.ident); - let value_tokens = variant_value(v)?; - let docstring = extract_docstring(&v.attrs)?; - let field_types = v.fields.iter().map(|f| &f.ty); - let field_docstrings = v - .fields - .iter() - .map(|f| extract_docstring(&f.attrs)) - .collect::>>()?; - - Ok(quote! { - .concat_str(#name) - #value_tokens - .concat_value(#fields_len) - #( - .concat_str(#field_names) - .concat(<#field_types as ::uniffi::Lower>::TYPE_ID_META) - // field defaults not yet supported for enums - .concat_bool(false) - .concat_long_str(#field_docstrings) - )* - .concat_long_str(#docstring) - }) - })) - .collect() -} - -#[derive(Default)] -pub struct EnumAttr { - pub non_exhaustive: Option, -} - -// So ErrorAttr can be used with `parse_macro_input!` -impl Parse for EnumAttr { - fn parse(input: ParseStream<'_>) -> syn::Result { - parse_comma_separated(input) - } -} - -impl UniffiAttributeArgs for EnumAttr { - fn parse_one(input: ParseStream<'_>) -> syn::Result { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::non_exhaustive) { - Ok(Self { - non_exhaustive: input.parse()?, - }) - } else { - Err(lookahead.error()) - } - } - - fn merge(self, other: Self) -> syn::Result { - Ok(Self { - non_exhaustive: either_attribute_arg(self.non_exhaustive, other.non_exhaustive)?, - }) - } -} +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::{Data, DataEnum, DeriveInput, Field, Index}; + +use crate::util::{ + create_metadata_items, derive_all_ffi_traits, ident_to_string, mod_path, tagged_impl_header, + try_metadata_value_from_usize, try_read_field, +}; + +pub fn expand_enum(input: DeriveInput, udl_mode: bool) -> syn::Result { + let enum_ = match input.data { + Data::Enum(e) => e, + _ => { + return Err(syn::Error::new( + Span::call_site(), + "This derive must only be used on enums", + )) + } + }; + let ident = &input.ident; + let ffi_converter_impl = enum_ffi_converter_impl(ident, &enum_, udl_mode); + + let meta_static_var = (!udl_mode).then(|| { + enum_meta_static_var(ident, &enum_).unwrap_or_else(syn::Error::into_compile_error) + }); + + Ok(quote! { + #ffi_converter_impl + #meta_static_var + }) +} + +pub(crate) fn enum_ffi_converter_impl( + ident: &Ident, + enum_: &DataEnum, + udl_mode: bool, +) -> TokenStream { + enum_or_error_ffi_converter_impl( + ident, + enum_, + udl_mode, + quote! { ::uniffi::metadata::codes::TYPE_ENUM }, + ) +} + +pub(crate) fn rich_error_ffi_converter_impl( + ident: &Ident, + enum_: &DataEnum, + udl_mode: bool, +) -> TokenStream { + enum_or_error_ffi_converter_impl( + ident, + enum_, + udl_mode, + quote! { ::uniffi::metadata::codes::TYPE_ENUM }, + ) +} + +fn enum_or_error_ffi_converter_impl( + ident: &Ident, + enum_: &DataEnum, + udl_mode: bool, + metadata_type_code: TokenStream, +) -> TokenStream { + let name = ident_to_string(ident); + let impl_spec = tagged_impl_header("FfiConverter", ident, udl_mode); + let derive_ffi_traits = derive_all_ffi_traits(ident, udl_mode); + let mod_path = match mod_path() { + Ok(p) => p, + Err(e) => return e.into_compile_error(), + }; + let write_match_arms = enum_.variants.iter().enumerate().map(|(i, v)| { + let v_ident = &v.ident; + let fields = v.fields.iter().map(|f| &f.ident); + let idx = Index::from(i + 1); + let write_fields = v.fields.iter().map(write_field); + + quote! { + Self::#v_ident { #(#fields),* } => { + ::uniffi::deps::bytes::BufMut::put_i32(buf, #idx); + #(#write_fields)* + } + } + }); + let write_impl = quote! { + match obj { #(#write_match_arms)* } + }; + + let try_read_match_arms = enum_.variants.iter().enumerate().map(|(i, v)| { + let idx = Index::from(i + 1); + let v_ident = &v.ident; + let try_read_fields = v.fields.iter().map(try_read_field); + + quote! { + #idx => Self::#v_ident { #(#try_read_fields)* }, + } + }); + let error_format_string = format!("Invalid {ident} enum value: {{}}"); + let try_read_impl = quote! { + ::uniffi::check_remaining(buf, 4)?; + + Ok(match ::uniffi::deps::bytes::Buf::get_i32(buf) { + #(#try_read_match_arms)* + v => ::uniffi::deps::anyhow::bail!(#error_format_string, v), + }) + }; + + quote! { + #[automatically_derived] + unsafe #impl_spec { + ::uniffi::ffi_converter_rust_buffer_lift_and_lower!(crate::UniFfiTag); + + fn write(obj: Self, buf: &mut ::std::vec::Vec) { + #write_impl + } + + fn try_read(buf: &mut &[::std::primitive::u8]) -> ::uniffi::deps::anyhow::Result { + #try_read_impl + } + + const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(#metadata_type_code) + .concat_str(#mod_path) + .concat_str(#name); + } + + #derive_ffi_traits + } +} + +fn write_field(f: &Field) -> TokenStream { + let ident = &f.ident; + let ty = &f.ty; + + quote! { + <#ty as ::uniffi::Lower>::write(#ident, buf); + } +} + +pub(crate) fn enum_meta_static_var(ident: &Ident, enum_: &DataEnum) -> syn::Result { + let name = ident_to_string(ident); + let module_path = mod_path()?; + + let mut metadata_expr = quote! { + ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::ENUM) + .concat_str(#module_path) + .concat_str(#name) + }; + metadata_expr.extend(variant_metadata(enum_)?); + Ok(create_metadata_items("enum", &name, metadata_expr, None)) +} + +pub fn variant_metadata(enum_: &DataEnum) -> syn::Result> { + let variants_len = + try_metadata_value_from_usize(enum_.variants.len(), "UniFFI limits enums to 256 variants")?; + std::iter::once(Ok(quote! { .concat_value(#variants_len) })) + .chain( + enum_.variants + .iter() + .map(|v| { + let fields_len = try_metadata_value_from_usize( + v.fields.len(), + "UniFFI limits enum variants to 256 fields", + )?; + + let field_names = v.fields + .iter() + .map(|f| { + f.ident + .as_ref() + .ok_or_else(|| + syn::Error::new_spanned( + v, + "UniFFI only supports enum variants with named fields (or no fields at all)", + ) + ) + .map(ident_to_string) + }) + .collect::>>()?; + + let name = ident_to_string(&v.ident); + let field_types = v.fields.iter().map(|f| &f.ty); + Ok(quote! { + .concat_str(#name) + .concat_value(#fields_len) + #( + .concat_str(#field_names) + .concat(<#field_types as ::uniffi::Lower>::TYPE_ID_META) + // field defaults not yet supported for enums + .concat_bool(false) + )* + }) + }) + ) + .collect() +} diff --git a/third_party/rust/uniffi_macros/src/error.rs b/third_party/rust/uniffi_macros/src/error.rs index 804b43800332..a2ee7cf60325 100644 --- a/third_party/rust/uniffi_macros/src/error.rs +++ b/third_party/rust/uniffi_macros/src/error.rs @@ -6,11 +6,11 @@ use syn::{ }; use crate::{ - enum_::{rich_error_ffi_converter_impl, variant_metadata, EnumAttr}, + enum_::{rich_error_ffi_converter_impl, variant_metadata}, util::{ - chain, create_metadata_items, derive_ffi_traits, either_attribute_arg, extract_docstring, - ident_to_string, kw, mod_path, parse_comma_separated, tagged_impl_header, - try_metadata_value_from_usize, AttributeSliceExt, UniffiAttributeArgs, + chain, create_metadata_items, derive_ffi_traits, either_attribute_arg, ident_to_string, kw, + mod_path, parse_comma_separated, tagged_impl_header, try_metadata_value_from_usize, + AttributeSliceExt, UniffiAttributeArgs, }, }; @@ -30,14 +30,13 @@ pub fn expand_error( } }; let ident = &input.ident; - let docstring = extract_docstring(&input.attrs)?; let mut attr: ErrorAttr = input.attrs.parse_uniffi_attr_args()?; if let Some(attr_from_udl_mode) = attr_from_udl_mode { attr = attr.merge(attr_from_udl_mode)?; } - let ffi_converter_impl = error_ffi_converter_impl(ident, &enum_, &attr, udl_mode)?; + let ffi_converter_impl = error_ffi_converter_impl(ident, &enum_, &attr, udl_mode); let meta_static_var = (!udl_mode).then(|| { - error_meta_static_var(ident, docstring, &enum_, &attr) + error_meta_static_var(ident, &enum_, attr.flat.is_some()) .unwrap_or_else(syn::Error::into_compile_error) }); @@ -68,23 +67,23 @@ fn error_ffi_converter_impl( enum_: &DataEnum, attr: &ErrorAttr, udl_mode: bool, -) -> syn::Result { - Ok(if attr.flat.is_some() { - flat_error_ffi_converter_impl(ident, enum_, udl_mode, attr) +) -> TokenStream { + if attr.flat.is_some() { + flat_error_ffi_converter_impl(ident, enum_, udl_mode, attr.with_try_read.is_some()) } else { - rich_error_ffi_converter_impl(ident, enum_, udl_mode, &attr.clone().try_into()?) - }) + rich_error_ffi_converter_impl(ident, enum_, udl_mode) + } } // FfiConverters for "flat errors" // -// These are errors where we only lower the to_string() value, rather than any associated data. +// These are errors where we only lower the to_string() value, rather than any assocated data. // We lower the to_string() value unconditionally, whether the enum has associated data or not. fn flat_error_ffi_converter_impl( ident: &Ident, enum_: &DataEnum, udl_mode: bool, - attr: &ErrorAttr, + implement_lift: bool, ) -> TokenStream { let name = ident_to_string(ident); let lower_impl_spec = tagged_impl_header("Lower", ident, udl_mode); @@ -96,7 +95,7 @@ fn flat_error_ffi_converter_impl( }; let lower_impl = { - let mut match_arms: Vec<_> = enum_.variants.iter().enumerate().map(|(i, v)| { + let match_arms = enum_.variants.iter().enumerate().map(|(i, v)| { let v_ident = &v.ident; let idx = Index::from(i + 1); @@ -106,12 +105,7 @@ fn flat_error_ffi_converter_impl( <::std::string::String as ::uniffi::Lower>::write(error_msg, buf); } } - }).collect(); - if attr.non_exhaustive.is_some() { - match_arms.push(quote! { - _ => panic!("Unexpected variant in non-exhaustive enum"), - }) - } + }); quote! { #[automatically_derived] @@ -134,7 +128,7 @@ fn flat_error_ffi_converter_impl( } }; - let lift_impl = if attr.with_try_read.is_some() { + let lift_impl = if implement_lift { let match_arms = enum_.variants.iter().enumerate().map(|(i, v)| { let v_ident = &v.ident; let idx = Index::from(i + 1); @@ -198,53 +192,42 @@ fn flat_error_ffi_converter_impl( pub(crate) fn error_meta_static_var( ident: &Ident, - docstring: String, enum_: &DataEnum, - attr: &ErrorAttr, + flat: bool, ) -> syn::Result { let name = ident_to_string(ident); let module_path = mod_path()?; - let flat = attr.flat.is_some(); - let non_exhaustive = attr.non_exhaustive.is_some(); let mut metadata_expr = quote! { - ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::ENUM) + ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::ERROR) + // first our is-flat flag + .concat_bool(#flat) + // followed by an enum .concat_str(#module_path) .concat_str(#name) - .concat_option_bool(Some(#flat)) - .concat_bool(false) // discr_type: None }; if flat { metadata_expr.extend(flat_error_variant_metadata(enum_)?) } else { metadata_expr.extend(variant_metadata(enum_)?); } - metadata_expr.extend(quote! { - .concat_bool(#non_exhaustive) - .concat_long_str(#docstring) - }); Ok(create_metadata_items("error", &name, metadata_expr, None)) } pub fn flat_error_variant_metadata(enum_: &DataEnum) -> syn::Result> { let variants_len = try_metadata_value_from_usize(enum_.variants.len(), "UniFFI limits enums to 256 variants")?; - std::iter::once(Ok(quote! { .concat_value(#variants_len) })) + Ok(std::iter::once(quote! { .concat_value(#variants_len) }) .chain(enum_.variants.iter().map(|v| { let name = ident_to_string(&v.ident); - let docstring = extract_docstring(&v.attrs)?; - Ok(quote! { - .concat_str(#name) - .concat_long_str(#docstring) - }) + quote! { .concat_str(#name) } })) - .collect() + .collect()) } -#[derive(Clone, Default)] +#[derive(Default)] pub struct ErrorAttr { - pub flat: Option, - pub with_try_read: Option, - pub non_exhaustive: Option, + flat: Option, + with_try_read: Option, } impl UniffiAttributeArgs for ErrorAttr { @@ -260,13 +243,8 @@ impl UniffiAttributeArgs for ErrorAttr { with_try_read: input.parse()?, ..Self::default() }) - } else if lookahead.peek(kw::non_exhaustive) { - Ok(Self { - non_exhaustive: input.parse()?, - ..Self::default() - }) } else if lookahead.peek(kw::handle_unknown_callback_error) { - // Not used anymore, but still allowed + // Not used anymore, but still lallowed Ok(Self::default()) } else { Err(lookahead.error()) @@ -277,7 +255,6 @@ impl UniffiAttributeArgs for ErrorAttr { Ok(Self { flat: either_attribute_arg(self.flat, other.flat)?, with_try_read: either_attribute_arg(self.with_try_read, other.with_try_read)?, - non_exhaustive: either_attribute_arg(self.non_exhaustive, other.non_exhaustive)?, }) } } @@ -288,25 +265,3 @@ impl Parse for ErrorAttr { parse_comma_separated(input) } } - -impl TryFrom for EnumAttr { - type Error = syn::Error; - - fn try_from(error_attr: ErrorAttr) -> Result { - if error_attr.flat.is_some() { - Err(syn::Error::new( - Span::call_site(), - "flat attribute not valid for rich enum errors", - )) - } else if error_attr.with_try_read.is_some() { - Err(syn::Error::new( - Span::call_site(), - "with_try_read attribute not valid for rich enum errors", - )) - } else { - Ok(EnumAttr { - non_exhaustive: error_attr.non_exhaustive, - }) - } - } -} diff --git a/third_party/rust/uniffi_macros/src/export.rs b/third_party/rust/uniffi_macros/src/export.rs index 41657a639e42..bbb16acf9019 100644 --- a/third_party/rust/uniffi_macros/src/export.rs +++ b/third_party/rust/uniffi_macros/src/export.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use proc_macro2::TokenStream; +use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, quote_spanned}; use syn::{visit_mut::VisitMut, Item, Type}; @@ -10,7 +10,6 @@ mod attributes; mod callback_interface; mod item; mod scaffolding; -mod trait_interface; mod utrait; use self::{ @@ -19,16 +18,20 @@ use self::{ gen_constructor_scaffolding, gen_ffi_function, gen_fn_scaffolding, gen_method_scaffolding, }, }; -use crate::util::{ident_to_string, mod_path}; -pub use attributes::{DefaultMap, ExportFnArgs, ExportedImplFnArgs}; +use crate::{ + object::interface_meta_static_var, + util::{ident_to_string, mod_path, tagged_impl_header}, +}; +pub use attributes::ExportAttributeArguments; pub use callback_interface::ffi_converter_callback_interface_impl; +use uniffi_meta::free_fn_symbol_name; // TODO(jplatte): Ensure no generics, … // TODO(jplatte): Aggregate errors instead of short-circuiting, wherever possible pub(crate) fn expand_export( mut item: Item, - all_args: proc_macro::TokenStream, + args: ExportAttributeArguments, udl_mode: bool, ) -> syn::Result { let mod_path = mod_path()?; @@ -38,17 +41,11 @@ pub(crate) fn expand_export( // new functions outside of the `impl`). rewrite_self_type(&mut item); - let metadata = ExportItem::new(item, all_args)?; + let metadata = ExportItem::new(item, &args)?; match metadata { - ExportItem::Function { sig, args } => { - gen_fn_scaffolding(sig, &args.async_runtime, udl_mode) - } - ExportItem::Impl { - items, - self_ident, - args, - } => { + ExportItem::Function { sig } => gen_fn_scaffolding(sig, &args, udl_mode), + ExportItem::Impl { items, self_ident } => { if let Some(rt) = &args.async_runtime { if items .iter() @@ -64,12 +61,8 @@ pub(crate) fn expand_export( let item_tokens: TokenStream = items .into_iter() .map(|item| match item { - ImplItem::Constructor(sig) => { - gen_constructor_scaffolding(sig, &args.async_runtime, udl_mode) - } - ImplItem::Method(sig) => { - gen_method_scaffolding(sig, &args.async_runtime, udl_mode) - } + ImplItem::Constructor(sig) => gen_constructor_scaffolding(sig, &args, udl_mode), + ImplItem::Method(sig) => gen_method_scaffolding(sig, &args, udl_mode), }) .collect::>()?; Ok(quote_spanned! { self_ident.span() => #item_tokens }) @@ -77,51 +70,111 @@ pub(crate) fn expand_export( ExportItem::Trait { items, self_ident, - with_foreign, - callback_interface_only: false, - docstring, - args, - } => trait_interface::gen_trait_scaffolding( - &mod_path, - args, - self_ident, - items, - udl_mode, - with_foreign, - docstring, - ), + callback_interface: false, + } => { + if let Some(rt) = args.async_runtime { + return Err(syn::Error::new_spanned(rt, "not supported for traits")); + } + + let name = ident_to_string(&self_ident); + let free_fn_ident = + Ident::new(&free_fn_symbol_name(&mod_path, &name), Span::call_site()); + + let free_tokens = quote! { + #[doc(hidden)] + #[no_mangle] + pub extern "C" fn #free_fn_ident( + ptr: *const ::std::ffi::c_void, + call_status: &mut ::uniffi::RustCallStatus + ) { + uniffi::rust_call(call_status, || { + assert!(!ptr.is_null()); + drop(unsafe { ::std::boxed::Box::from_raw(ptr as *mut std::sync::Arc) }); + Ok(()) + }); + } + }; + + let impl_tokens: TokenStream = items + .into_iter() + .map(|item| match item { + ImplItem::Method(sig) => { + if sig.is_async { + return Err(syn::Error::new( + sig.span, + "async trait methods are not supported", + )); + } + gen_method_scaffolding(sig, &args, udl_mode) + } + _ => unreachable!("traits have no constructors"), + }) + .collect::>()?; + + let meta_static_var = (!udl_mode).then(|| { + interface_meta_static_var(&self_ident, true, &mod_path) + .unwrap_or_else(syn::Error::into_compile_error) + }); + let ffi_converter_tokens = ffi_converter_trait_impl(&self_ident, false); + + Ok(quote_spanned! { self_ident.span() => + #meta_static_var + #free_tokens + #ffi_converter_tokens + #impl_tokens + }) + } ExportItem::Trait { items, self_ident, - callback_interface_only: true, - docstring, - .. + callback_interface: true, } => { let trait_name = ident_to_string(&self_ident); - let trait_impl_ident = callback_interface::trait_impl_ident(&trait_name); - let trait_impl = callback_interface::trait_impl(&mod_path, &self_ident, &items) - .unwrap_or_else(|e| e.into_compile_error()); - let metadata_items = (!udl_mode).then(|| { - let items = - callback_interface::metadata_items(&self_ident, &items, &mod_path, docstring) - .unwrap_or_else(|e| vec![e.into_compile_error()]); - quote! { #(#items)* } - }); - let ffi_converter_tokens = - ffi_converter_callback_interface_impl(&self_ident, &trait_impl_ident, udl_mode); + let trait_impl_ident = Ident::new( + &format!("UniFFICallbackHandler{trait_name}"), + Span::call_site(), + ); + let internals_ident = Ident::new( + &format!( + "UNIFFI_FOREIGN_CALLBACK_INTERNALS_{}", + trait_name.to_ascii_uppercase() + ), + Span::call_site(), + ); + + let trait_impl = callback_interface::trait_impl( + &trait_impl_ident, + &self_ident, + &internals_ident, + &items, + ) + .unwrap_or_else(|e| e.into_compile_error()); + let metadata_items = callback_interface::metadata_items(&self_ident, &items, &mod_path) + .unwrap_or_else(|e| vec![e.into_compile_error()]); + + let init_ident = Ident::new( + &uniffi_meta::init_callback_fn_symbol_name(&mod_path, &trait_name), + Span::call_site(), + ); Ok(quote! { - #trait_impl + #[doc(hidden)] + static #internals_ident: ::uniffi::ForeignCallbackInternals = ::uniffi::ForeignCallbackInternals::new(); - #ffi_converter_tokens + #[doc(hidden)] + #[no_mangle] + pub extern "C" fn #init_ident(callback: ::uniffi::ForeignCallback, _: &mut ::uniffi::RustCallStatus) { + #internals_ident.set_callback(callback); + } - #metadata_items + #trait_impl + + #(#metadata_items)* }) } ExportItem::Struct { self_ident, uniffi_traits, - .. } => { assert!(!udl_mode); utrait::expand_uniffi_trait_export(self_ident, uniffi_traits) @@ -129,6 +182,62 @@ pub(crate) fn expand_export( } } +pub(crate) fn ffi_converter_trait_impl(trait_ident: &Ident, udl_mode: bool) -> TokenStream { + let impl_spec = tagged_impl_header("FfiConverterArc", "e! { dyn #trait_ident }, udl_mode); + let lift_ref_impl_spec = tagged_impl_header("LiftRef", "e! { dyn #trait_ident }, udl_mode); + let name = ident_to_string(trait_ident); + let mod_path = match mod_path() { + Ok(p) => p, + Err(e) => return e.into_compile_error(), + }; + + quote! { + // All traits must be `Sync + Send`. The generated scaffolding will fail to compile + // if they are not, but unfortunately it fails with an unactionably obscure error message. + // By asserting the requirement explicitly, we help Rust produce a more scrutable error message + // and thus help the user debug why the requirement isn't being met. + uniffi::deps::static_assertions::assert_impl_all!(dyn #trait_ident: Sync, Send); + + unsafe #impl_spec { + type FfiType = *const ::std::os::raw::c_void; + + fn lower(obj: ::std::sync::Arc) -> Self::FfiType { + ::std::boxed::Box::into_raw(::std::boxed::Box::new(obj)) as *const ::std::os::raw::c_void + } + + fn try_lift(v: Self::FfiType) -> ::uniffi::Result<::std::sync::Arc> { + let foreign_arc = ::std::boxed::Box::leak(unsafe { Box::from_raw(v as *mut ::std::sync::Arc) }); + // Take a clone for our own use. + Ok(::std::sync::Arc::clone(foreign_arc)) + } + + fn write(obj: ::std::sync::Arc, buf: &mut Vec) { + ::uniffi::deps::static_assertions::const_assert!(::std::mem::size_of::<*const ::std::ffi::c_void>() <= 8); + ::uniffi::deps::bytes::BufMut::put_u64( + buf, + >::lower(obj) as u64, + ); + } + + fn try_read(buf: &mut &[u8]) -> ::uniffi::Result<::std::sync::Arc> { + ::uniffi::deps::static_assertions::const_assert!(::std::mem::size_of::<*const ::std::ffi::c_void>() <= 8); + ::uniffi::check_remaining(buf, 8)?; + >::try_lift( + ::uniffi::deps::bytes::Buf::get_u64(buf) as Self::FfiType) + } + + const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_INTERFACE) + .concat_str(#mod_path) + .concat_str(#name) + .concat_bool(true); + } + + unsafe #lift_ref_impl_spec { + type LiftType = ::std::sync::Arc; + } + } +} + /// Rewrite Self type alias usage in an impl block to the type itself. /// /// For example, diff --git a/third_party/rust/uniffi_macros/src/export/attributes.rs b/third_party/rust/uniffi_macros/src/export/attributes.rs dissimilarity index 66% index be7e8902e440..c3edcd592029 100644 --- a/third_party/rust/uniffi_macros/src/export/attributes.rs +++ b/third_party/rust/uniffi_macros/src/export/attributes.rs @@ -1,403 +1,173 @@ -use std::collections::{HashMap, HashSet}; - -use crate::{ - default::DefaultValue, - util::{either_attribute_arg, kw, parse_comma_separated, UniffiAttributeArgs}, -}; - -use proc_macro2::TokenStream; -use quote::ToTokens; -use syn::{ - parenthesized, - parse::{Parse, ParseStream}, - Attribute, Ident, LitStr, Meta, PathArguments, PathSegment, Token, -}; -use uniffi_meta::UniffiTraitDiscriminants; - -#[derive(Default)] -pub struct ExportTraitArgs { - pub(crate) async_runtime: Option, - pub(crate) callback_interface: Option, - pub(crate) with_foreign: Option, -} - -impl Parse for ExportTraitArgs { - fn parse(input: ParseStream<'_>) -> syn::Result { - parse_comma_separated(input) - } -} - -impl UniffiAttributeArgs for ExportTraitArgs { - fn parse_one(input: ParseStream<'_>) -> syn::Result { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::async_runtime) { - let _: kw::async_runtime = input.parse()?; - let _: Token![=] = input.parse()?; - Ok(Self { - async_runtime: Some(input.parse()?), - ..Self::default() - }) - } else if lookahead.peek(kw::callback_interface) { - Ok(Self { - callback_interface: input.parse()?, - ..Self::default() - }) - } else if lookahead.peek(kw::with_foreign) { - Ok(Self { - with_foreign: input.parse()?, - ..Self::default() - }) - } else { - Ok(Self::default()) - } - } - - fn merge(self, other: Self) -> syn::Result { - let merged = Self { - async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?, - callback_interface: either_attribute_arg( - self.callback_interface, - other.callback_interface, - )?, - with_foreign: either_attribute_arg(self.with_foreign, other.with_foreign)?, - }; - if merged.callback_interface.is_some() && merged.with_foreign.is_some() { - return Err(syn::Error::new( - merged.callback_interface.unwrap().span, - "`callback_interface` and `with_foreign` are mutually exclusive", - )); - } - Ok(merged) - } -} - -#[derive(Clone, Default)] -pub struct ExportFnArgs { - pub(crate) async_runtime: Option, - pub(crate) name: Option, - pub(crate) defaults: DefaultMap, -} - -impl Parse for ExportFnArgs { - fn parse(input: ParseStream<'_>) -> syn::Result { - parse_comma_separated(input) - } -} - -impl UniffiAttributeArgs for ExportFnArgs { - fn parse_one(input: ParseStream<'_>) -> syn::Result { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::async_runtime) { - let _: kw::async_runtime = input.parse()?; - let _: Token![=] = input.parse()?; - Ok(Self { - async_runtime: Some(input.parse()?), - ..Self::default() - }) - } else if lookahead.peek(kw::name) { - let _: kw::name = input.parse()?; - let _: Token![=] = input.parse()?; - let name = Some(input.parse::()?.value()); - Ok(Self { - name, - ..Self::default() - }) - } else if lookahead.peek(kw::default) { - Ok(Self { - defaults: DefaultMap::parse(input)?, - ..Self::default() - }) - } else { - Err(syn::Error::new( - input.span(), - format!("uniffi::export attribute `{input}` is not supported here."), - )) - } - } - - fn merge(self, other: Self) -> syn::Result { - Ok(Self { - async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?, - name: either_attribute_arg(self.name, other.name)?, - defaults: self.defaults.merge(other.defaults), - }) - } -} - -#[derive(Default)] -pub struct ExportImplArgs { - pub(crate) async_runtime: Option, -} - -impl Parse for ExportImplArgs { - fn parse(input: ParseStream<'_>) -> syn::Result { - parse_comma_separated(input) - } -} - -impl UniffiAttributeArgs for ExportImplArgs { - fn parse_one(input: ParseStream<'_>) -> syn::Result { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::async_runtime) { - let _: kw::async_runtime = input.parse()?; - let _: Token![=] = input.parse()?; - Ok(Self { - async_runtime: Some(input.parse()?), - }) - } else { - Err(syn::Error::new( - input.span(), - format!("uniffi::export attribute `{input}` is not supported here."), - )) - } - } - - fn merge(self, other: Self) -> syn::Result { - Ok(Self { - async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?, - }) - } -} - -#[derive(Default)] -pub struct ExportStructArgs { - pub(crate) traits: HashSet, -} - -impl Parse for ExportStructArgs { - fn parse(input: ParseStream<'_>) -> syn::Result { - parse_comma_separated(input) - } -} - -impl UniffiAttributeArgs for ExportStructArgs { - fn parse_one(input: ParseStream<'_>) -> syn::Result { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::Debug) { - input.parse::>()?; - Ok(Self { - traits: HashSet::from([UniffiTraitDiscriminants::Debug]), - }) - } else if lookahead.peek(kw::Display) { - input.parse::>()?; - Ok(Self { - traits: HashSet::from([UniffiTraitDiscriminants::Display]), - }) - } else if lookahead.peek(kw::Hash) { - input.parse::>()?; - Ok(Self { - traits: HashSet::from([UniffiTraitDiscriminants::Hash]), - }) - } else if lookahead.peek(kw::Eq) { - input.parse::>()?; - Ok(Self { - traits: HashSet::from([UniffiTraitDiscriminants::Eq]), - }) - } else { - Err(syn::Error::new( - input.span(), - format!( - "uniffi::export struct attributes must be builtin trait names; `{input}` is invalid" - ), - )) - } - } - - fn merge(self, other: Self) -> syn::Result { - let mut traits = self.traits; - traits.extend(other.traits); - Ok(Self { traits }) - } -} - -#[derive(Clone)] -pub(crate) enum AsyncRuntime { - Tokio(LitStr), -} - -impl Parse for AsyncRuntime { - fn parse(input: ParseStream<'_>) -> syn::Result { - let lit: LitStr = input.parse()?; - match lit.value().as_str() { - "tokio" => Ok(Self::Tokio(lit)), - _ => Err(syn::Error::new_spanned( - lit, - "unknown async runtime, currently only `tokio` is supported", - )), - } - } -} - -impl ToTokens for AsyncRuntime { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - AsyncRuntime::Tokio(lit) => lit.to_tokens(tokens), - } - } -} - -/// Arguments for function inside an impl block -/// -/// This stores the parsed arguments for `uniffi::constructor` and `uniffi::method` -#[derive(Clone, Default)] -pub struct ExportedImplFnArgs { - pub(crate) name: Option, - pub(crate) defaults: DefaultMap, -} - -impl Parse for ExportedImplFnArgs { - fn parse(input: ParseStream<'_>) -> syn::Result { - parse_comma_separated(input) - } -} - -impl UniffiAttributeArgs for ExportedImplFnArgs { - fn parse_one(input: ParseStream<'_>) -> syn::Result { - let lookahead = input.lookahead1(); - if lookahead.peek(kw::name) { - let _: kw::name = input.parse()?; - let _: Token![=] = input.parse()?; - let name = Some(input.parse::()?.value()); - Ok(Self { - name, - ..Self::default() - }) - } else if lookahead.peek(kw::default) { - Ok(Self { - defaults: DefaultMap::parse(input)?, - ..Self::default() - }) - } else { - Err(syn::Error::new( - input.span(), - format!("uniffi::constructor/method attribute `{input}` is not supported here."), - )) - } - } - - fn merge(self, other: Self) -> syn::Result { - Ok(Self { - name: either_attribute_arg(self.name, other.name)?, - defaults: self.defaults.merge(other.defaults), - }) - } -} - -#[derive(Default)] -pub(super) struct ExportedImplFnAttributes { - pub constructor: bool, - pub args: ExportedImplFnArgs, -} - -impl ExportedImplFnAttributes { - pub fn new(attrs: &[Attribute]) -> syn::Result { - let mut this = Self::default(); - for attr in attrs { - let segs = &attr.path().segments; - - let fst = segs - .first() - .expect("attributes have at least one path segment"); - if fst.ident != "uniffi" { - continue; - } - ensure_no_path_args(fst)?; - - let args = match &attr.meta { - Meta::List(_) => attr.parse_args::()?, - _ => Default::default(), - }; - this.args = args; - - if segs.len() != 2 { - return Err(syn::Error::new_spanned( - segs, - "unsupported uniffi attribute", - )); - } - let snd = &segs[1]; - ensure_no_path_args(snd)?; - - match snd.ident.to_string().as_str() { - "constructor" => { - if this.constructor { - return Err(syn::Error::new_spanned( - attr, - "duplicate constructor attribute", - )); - } - this.constructor = true; - } - "method" => { - if this.constructor { - return Err(syn::Error::new_spanned( - attr, - "confused constructor/method attributes", - )); - } - } - _ => return Err(syn::Error::new_spanned(snd, "unknown uniffi attribute")), - } - } - - Ok(this) - } -} - -fn ensure_no_path_args(seg: &PathSegment) -> syn::Result<()> { - if matches!(seg.arguments, PathArguments::None) { - Ok(()) - } else { - Err(syn::Error::new_spanned(&seg.arguments, "unexpected syntax")) - } -} - -/// Maps arguments to defaults for functions -#[derive(Clone, Default)] -pub struct DefaultMap { - map: HashMap, -} - -impl DefaultMap { - pub fn merge(self, other: Self) -> Self { - let mut map = self.map; - map.extend(other.map); - Self { map } - } - - pub fn remove(&mut self, ident: &Ident) -> Option { - self.map.remove(ident) - } - - pub fn idents(&self) -> Vec<&Ident> { - self.map.keys().collect() - } -} - -impl Parse for DefaultMap { - fn parse(input: ParseStream<'_>) -> syn::Result { - let _: kw::default = input.parse()?; - let content; - let _ = parenthesized!(content in input); - let pairs = content.parse_terminated(DefaultPair::parse, Token![,])?; - Ok(Self { - map: pairs.into_iter().map(|p| (p.name, p.value)).collect(), - }) - } -} - -pub struct DefaultPair { - pub name: Ident, - pub eq_token: Token![=], - pub value: DefaultValue, -} - -impl Parse for DefaultPair { - fn parse(input: ParseStream<'_>) -> syn::Result { - Ok(Self { - name: input.parse()?, - eq_token: input.parse()?, - value: input.parse()?, - }) - } -} +use crate::util::{either_attribute_arg, kw, parse_comma_separated, UniffiAttributeArgs}; + +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{ + parse::{Parse, ParseStream}, + Attribute, LitStr, Meta, PathArguments, PathSegment, Token, +}; + +#[derive(Default)] +pub struct ExportAttributeArguments { + pub(crate) async_runtime: Option, + pub(crate) callback_interface: Option, + pub(crate) constructor: Option, + // tried to make this a vec but that got messy quickly... + pub(crate) trait_debug: Option, + pub(crate) trait_display: Option, + pub(crate) trait_hash: Option, + pub(crate) trait_eq: Option, +} + +impl Parse for ExportAttributeArguments { + fn parse(input: ParseStream<'_>) -> syn::Result { + parse_comma_separated(input) + } +} + +impl UniffiAttributeArgs for ExportAttributeArguments { + fn parse_one(input: ParseStream<'_>) -> syn::Result { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::async_runtime) { + let _: kw::async_runtime = input.parse()?; + let _: Token![=] = input.parse()?; + Ok(Self { + async_runtime: Some(input.parse()?), + ..Self::default() + }) + } else if lookahead.peek(kw::callback_interface) { + Ok(Self { + callback_interface: input.parse()?, + ..Self::default() + }) + } else if lookahead.peek(kw::constructor) { + Ok(Self { + constructor: input.parse()?, + ..Self::default() + }) + } else if lookahead.peek(kw::Debug) { + Ok(Self { + trait_debug: input.parse()?, + ..Self::default() + }) + } else if lookahead.peek(kw::Display) { + Ok(Self { + trait_display: input.parse()?, + ..Self::default() + }) + } else if lookahead.peek(kw::Hash) { + Ok(Self { + trait_hash: input.parse()?, + ..Self::default() + }) + } else if lookahead.peek(kw::Eq) { + Ok(Self { + trait_eq: input.parse()?, + ..Self::default() + }) + } else { + Ok(Self::default()) + } + } + + fn merge(self, other: Self) -> syn::Result { + Ok(Self { + async_runtime: either_attribute_arg(self.async_runtime, other.async_runtime)?, + callback_interface: either_attribute_arg( + self.callback_interface, + other.callback_interface, + )?, + constructor: either_attribute_arg(self.constructor, other.constructor)?, + trait_debug: either_attribute_arg(self.trait_debug, other.trait_debug)?, + trait_display: either_attribute_arg(self.trait_display, other.trait_display)?, + trait_hash: either_attribute_arg(self.trait_hash, other.trait_hash)?, + trait_eq: either_attribute_arg(self.trait_eq, other.trait_eq)?, + }) + } +} + +pub(crate) enum AsyncRuntime { + Tokio(LitStr), +} + +impl Parse for AsyncRuntime { + fn parse(input: ParseStream<'_>) -> syn::Result { + let lit: LitStr = input.parse()?; + match lit.value().as_str() { + "tokio" => Ok(Self::Tokio(lit)), + _ => Err(syn::Error::new_spanned( + lit, + "unknown async runtime, currently only `tokio` is supported", + )), + } + } +} + +impl ToTokens for AsyncRuntime { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + AsyncRuntime::Tokio(lit) => lit.to_tokens(tokens), + } + } +} + +#[derive(Default)] +pub(super) struct ExportedImplFnAttributes { + pub constructor: bool, +} + +impl ExportedImplFnAttributes { + pub fn new(attrs: &[Attribute]) -> syn::Result { + let mut this = Self::default(); + for attr in attrs { + let segs = &attr.path().segments; + + let fst = segs + .first() + .expect("attributes have at least one path segment"); + if fst.ident != "uniffi" { + continue; + } + ensure_no_path_args(fst)?; + + if let Meta::List(_) | Meta::NameValue(_) = &attr.meta { + return Err(syn::Error::new_spanned( + &attr.meta, + "attribute arguments are not currently recognized in this position", + )); + } + + if segs.len() != 2 { + return Err(syn::Error::new_spanned( + segs, + "unsupported uniffi attribute", + )); + } + let snd = &segs[1]; + ensure_no_path_args(snd)?; + + match snd.ident.to_string().as_str() { + "constructor" => { + if this.constructor { + return Err(syn::Error::new_spanned( + attr, + "duplicate constructor attribute", + )); + } + this.constructor = true; + } + _ => return Err(syn::Error::new_spanned(snd, "unknown uniffi attribute")), + } + } + + Ok(this) + } +} + +fn ensure_no_path_args(seg: &PathSegment) -> syn::Result<()> { + if matches!(seg.arguments, PathArguments::None) { + Ok(()) + } else { + Err(syn::Error::new_spanned(&seg.arguments, "unexpected syntax")) + } +} diff --git a/third_party/rust/uniffi_macros/src/export/callback_interface.rs b/third_party/rust/uniffi_macros/src/export/callback_interface.rs dissimilarity index 63% index fe145384ec73..2f2561bbc223 100644 --- a/third_party/rust/uniffi_macros/src/export/callback_interface.rs +++ b/third_party/rust/uniffi_macros/src/export/callback_interface.rs @@ -1,263 +1,175 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use crate::{ - export::ImplItem, - fnsig::{FnKind, FnSignature, ReceiverArg}, - util::{ - create_metadata_items, derive_ffi_traits, ident_to_string, mod_path, tagged_impl_header, - }, -}; -use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote}; -use std::iter; -use syn::Ident; - -/// Generate a trait impl that calls foreign callbacks -/// -/// This generates: -/// * A `repr(C)` VTable struct where each field is the FFI function for the trait method. -/// * A FFI function for foreign code to set their VTable for the interface -/// * An implementation of the trait using that VTable -pub(super) fn trait_impl( - mod_path: &str, - trait_ident: &Ident, - items: &[ImplItem], -) -> syn::Result { - let trait_name = ident_to_string(trait_ident); - let trait_impl_ident = trait_impl_ident(&trait_name); - let vtable_type = format_ident!("UniFfiTraitVtable{trait_name}"); - let vtable_cell = format_ident!("UNIFFI_TRAIT_CELL_{}", trait_name.to_uppercase()); - let init_ident = Ident::new( - &uniffi_meta::init_callback_vtable_fn_symbol_name(mod_path, &trait_name), - Span::call_site(), - ); - let methods = items - .iter() - .map(|item| match item { - ImplItem::Constructor(sig) => Err(syn::Error::new( - sig.span, - "Constructors not allowed in trait interfaces", - )), - ImplItem::Method(sig) => Ok(sig), - }) - .collect::>>()?; - - let vtable_fields = methods.iter() - .map(|sig| { - let ident = &sig.ident; - let param_names = sig.scaffolding_param_names(); - let param_types = sig.scaffolding_param_types(); - let lift_return = sig.lift_return_impl(); - if !sig.is_async { - quote! { - #ident: extern "C" fn( - uniffi_handle: u64, - #(#param_names: #param_types,)* - uniffi_out_return: &mut #lift_return::ReturnType, - uniffi_out_call_status: &mut ::uniffi::RustCallStatus, - ), - } - } else { - quote! { - #ident: extern "C" fn( - uniffi_handle: u64, - #(#param_names: #param_types,)* - uniffi_future_callback: ::uniffi::ForeignFutureCallback<#lift_return::ReturnType>, - uniffi_callback_data: u64, - uniffi_out_return: &mut ::uniffi::ForeignFuture, - ), - } - } - }); - - let trait_impl_methods = methods - .iter() - .map(|sig| gen_method_impl(sig, &vtable_cell)) - .collect::>>()?; - let has_async_method = methods.iter().any(|m| m.is_async); - let impl_attributes = has_async_method.then(|| quote! { #[::async_trait::async_trait] }); - - Ok(quote! { - struct #vtable_type { - #(#vtable_fields)* - uniffi_free: extern "C" fn(handle: u64), - } - - static #vtable_cell: ::uniffi::UniffiForeignPointerCell::<#vtable_type> = ::uniffi::UniffiForeignPointerCell::<#vtable_type>::new(); - - #[no_mangle] - extern "C" fn #init_ident(vtable: ::std::ptr::NonNull<#vtable_type>) { - #vtable_cell.set(vtable); - } - - #[derive(Debug)] - struct #trait_impl_ident { - handle: u64, - } - - impl #trait_impl_ident { - fn new(handle: u64) -> Self { - Self { handle } - } - } - - ::uniffi::deps::static_assertions::assert_impl_all!(#trait_impl_ident: ::core::marker::Send); - - #impl_attributes - impl #trait_ident for #trait_impl_ident { - #(#trait_impl_methods)* - } - - impl ::std::ops::Drop for #trait_impl_ident { - fn drop(&mut self) { - let vtable = #vtable_cell.get(); - (vtable.uniffi_free)(self.handle); - } - } - }) -} - -pub fn trait_impl_ident(trait_name: &str) -> Ident { - Ident::new( - &format!("UniFFICallbackHandler{trait_name}"), - Span::call_site(), - ) -} - -pub fn ffi_converter_callback_interface_impl( - trait_ident: &Ident, - trait_impl_ident: &Ident, - udl_mode: bool, -) -> TokenStream { - let trait_name = ident_to_string(trait_ident); - let dyn_trait = quote! { dyn #trait_ident }; - let box_dyn_trait = quote! { ::std::boxed::Box<#dyn_trait> }; - let lift_impl_spec = tagged_impl_header("Lift", &box_dyn_trait, udl_mode); - let derive_ffi_traits = derive_ffi_traits(&box_dyn_trait, udl_mode, &["LiftRef", "LiftReturn"]); - let mod_path = match mod_path() { - Ok(p) => p, - Err(e) => return e.into_compile_error(), - }; - - quote! { - #[doc(hidden)] - #[automatically_derived] - unsafe #lift_impl_spec { - type FfiType = u64; - - fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result { - Ok(::std::boxed::Box::new(<#trait_impl_ident>::new(v))) - } - - fn try_read(buf: &mut &[u8]) -> ::uniffi::deps::anyhow::Result { - use uniffi::deps::bytes::Buf; - ::uniffi::check_remaining(buf, 8)?; - >::try_lift(buf.get_u64()) - } - - const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code( - ::uniffi::metadata::codes::TYPE_CALLBACK_INTERFACE, - ) - .concat_str(#mod_path) - .concat_str(#trait_name); - } - - #derive_ffi_traits - } -} - -/// Generate a single method for [trait_impl]. This implements a trait method by invoking a -/// foreign-supplied callback. -fn gen_method_impl(sig: &FnSignature, vtable_cell: &Ident) -> syn::Result { - let FnSignature { - ident, - is_async, - return_ty, - kind, - receiver, - name, - span, - .. - } = sig; - - if !matches!(kind, FnKind::TraitMethod { .. }) { - return Err(syn::Error::new( - *span, - format!( - "Internal UniFFI error: Unexpected function kind for callback interface {name}: {kind:?}", - ), - )); - } - - let self_param = match receiver { - Some(ReceiverArg::Ref) => quote! { &self }, - Some(ReceiverArg::Arc) => quote! { self: Arc }, - None => { - return Err(syn::Error::new( - *span, - "callback interface methods must take &self as their first argument", - )); - } - }; - - let params = sig.params(); - let lower_exprs = sig.args.iter().map(|a| { - let lower_impl = a.lower_impl(); - let ident = &a.ident; - quote! { #lower_impl::lower(#ident) } - }); - - let lift_return = sig.lift_return_impl(); - - if !is_async { - Ok(quote! { - fn #ident(#self_param, #(#params),*) -> #return_ty { - let vtable = #vtable_cell.get(); - let mut uniffi_call_status = ::uniffi::RustCallStatus::new(); - let mut uniffi_return_value: #lift_return::ReturnType = ::uniffi::FfiDefault::ffi_default(); - (vtable.#ident)(self.handle, #(#lower_exprs,)* &mut uniffi_return_value, &mut uniffi_call_status); - #lift_return::lift_foreign_return(uniffi_return_value, uniffi_call_status) - } - }) - } else { - Ok(quote! { - async fn #ident(#self_param, #(#params),*) -> #return_ty { - let vtable = #vtable_cell.get(); - ::uniffi::foreign_async_call::<_, #return_ty, crate::UniFfiTag>(move |uniffi_future_callback, uniffi_future_callback_data| { - let mut uniffi_foreign_future: ::uniffi::ForeignFuture = ::uniffi::FfiDefault::ffi_default(); - (vtable.#ident)(self.handle, #(#lower_exprs,)* uniffi_future_callback, uniffi_future_callback_data, &mut uniffi_foreign_future); - uniffi_foreign_future - }).await - } - }) - } -} - -pub(super) fn metadata_items( - self_ident: &Ident, - items: &[ImplItem], - module_path: &str, - docstring: String, -) -> syn::Result> { - let trait_name = ident_to_string(self_ident); - let callback_interface_items = create_metadata_items( - "callback_interface", - &trait_name, - quote! { - ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::CALLBACK_INTERFACE) - .concat_str(#module_path) - .concat_str(#trait_name) - .concat_long_str(#docstring) - }, - None, - ); - - iter::once(Ok(callback_interface_items)) - .chain(items.iter().map(|item| match item { - ImplItem::Method(sig) => sig.metadata_items_for_callback_interface(), - _ => unreachable!("traits have no constructors"), - })) - .collect() -} +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use crate::{ + export::ImplItem, + fnsig::{FnKind, FnSignature, ReceiverArg}, + util::{create_metadata_items, ident_to_string, mod_path, tagged_impl_header}, +}; +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use std::iter; +use syn::Ident; + +pub(super) fn trait_impl( + ident: &Ident, + trait_ident: &Ident, + internals_ident: &Ident, + items: &[ImplItem], +) -> syn::Result { + let trait_impl_methods = items + .iter() + .map(|item| match item { + ImplItem::Method(sig) => gen_method_impl(sig, internals_ident), + _ => unreachable!("traits have no constructors"), + }) + .collect::>()?; + let ffi_converter_tokens = ffi_converter_callback_interface_impl(trait_ident, ident, false); + + Ok(quote! { + #[doc(hidden)] + #[derive(Debug)] + struct #ident { + handle: u64, + } + + impl #ident { + fn new(handle: u64) -> Self { + Self { handle } + } + } + + impl ::std::ops::Drop for #ident { + fn drop(&mut self) { + #internals_ident.invoke_callback::<(), crate::UniFfiTag>( + self.handle, uniffi::IDX_CALLBACK_FREE, Default::default() + ) + } + } + + ::uniffi::deps::static_assertions::assert_impl_all!(#ident: Send); + + impl #trait_ident for #ident { + #trait_impl_methods + } + + #ffi_converter_tokens + }) +} + +pub fn ffi_converter_callback_interface_impl( + trait_ident: &Ident, + trait_impl_ident: &Ident, + udl_mode: bool, +) -> TokenStream { + let name = ident_to_string(trait_ident); + let dyn_trait = quote! { dyn #trait_ident }; + let box_dyn_trait = quote! { ::std::boxed::Box<#dyn_trait> }; + let lift_impl_spec = tagged_impl_header("Lift", &box_dyn_trait, udl_mode); + let lift_ref_impl_spec = tagged_impl_header("LiftRef", &dyn_trait, udl_mode); + let mod_path = match mod_path() { + Ok(p) => p, + Err(e) => return e.into_compile_error(), + }; + + quote! { + #[doc(hidden)] + #[automatically_derived] + unsafe #lift_impl_spec { + type FfiType = u64; + + fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result { + Ok(::std::boxed::Box::new(<#trait_impl_ident>::new(v))) + } + + fn try_read(buf: &mut &[u8]) -> ::uniffi::deps::anyhow::Result { + use uniffi::deps::bytes::Buf; + ::uniffi::check_remaining(buf, 8)?; + >::try_lift(buf.get_u64()) + } + + const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code( + ::uniffi::metadata::codes::TYPE_CALLBACK_INTERFACE, + ) + .concat_str(#mod_path) + .concat_str(#name); + } + + unsafe #lift_ref_impl_spec { + type LiftType = #box_dyn_trait; + } + } +} + +fn gen_method_impl(sig: &FnSignature, internals_ident: &Ident) -> syn::Result { + let FnSignature { + ident, + return_ty, + kind, + receiver, + .. + } = sig; + let index = match kind { + // Note: the callback index is 1-based, since 0 is reserved for the free function + FnKind::TraitMethod { index, .. } => index + 1, + k => { + return Err(syn::Error::new( + sig.span, + format!( + "Internal UniFFI error: Unexpected function kind for callback interface {k:?}" + ), + )); + } + }; + + let self_param = match receiver { + None => { + return Err(syn::Error::new( + sig.span, + "callback interface methods must take &self as their first argument", + )); + } + Some(ReceiverArg::Ref) => quote! { &self }, + Some(ReceiverArg::Arc) => quote! { self: Arc }, + }; + let params = sig.params(); + let buf_ident = Ident::new("uniffi_args_buf", Span::call_site()); + let write_exprs = sig.write_exprs(&buf_ident); + + Ok(quote! { + fn #ident(#self_param, #(#params),*) -> #return_ty { + #[allow(unused_mut)] + let mut #buf_ident = ::std::vec::Vec::new(); + #(#write_exprs;)* + let uniffi_args_rbuf = uniffi::RustBuffer::from_vec(#buf_ident); + + #internals_ident.invoke_callback::<#return_ty, crate::UniFfiTag>(self.handle, #index, uniffi_args_rbuf) + } + }) +} + +pub(super) fn metadata_items( + self_ident: &Ident, + items: &[ImplItem], + module_path: &str, +) -> syn::Result> { + let trait_name = ident_to_string(self_ident); + let callback_interface_items = create_metadata_items( + "callback_interface", + &trait_name, + quote! { + ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::CALLBACK_INTERFACE) + .concat_str(#module_path) + .concat_str(#trait_name) + }, + None, + ); + + iter::once(Ok(callback_interface_items)) + .chain(items.iter().map(|item| match item { + ImplItem::Method(sig) => sig.metadata_items(), + _ => unreachable!("traits have no constructors"), + })) + .collect() +} diff --git a/third_party/rust/uniffi_macros/src/export/item.rs b/third_party/rust/uniffi_macros/src/export/item.rs index da3c9455c888..98c7d0ebe262 100644 --- a/third_party/rust/uniffi_macros/src/export/item.rs +++ b/third_party/rust/uniffi_macros/src/export/item.rs @@ -3,34 +3,24 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use crate::fnsig::FnSignature; -use proc_macro::TokenStream; use proc_macro2::{Ident, Span}; use quote::ToTokens; -use super::attributes::{ - ExportFnArgs, ExportImplArgs, ExportStructArgs, ExportTraitArgs, ExportedImplFnArgs, - ExportedImplFnAttributes, -}; -use crate::util::extract_docstring; +use super::attributes::{ExportAttributeArguments, ExportedImplFnAttributes}; use uniffi_meta::UniffiTraitDiscriminants; pub(super) enum ExportItem { Function { sig: FnSignature, - args: ExportFnArgs, }, Impl { self_ident: Ident, items: Vec, - args: ExportImplArgs, }, Trait { self_ident: Ident, items: Vec, - with_foreign: bool, - callback_interface_only: bool, - docstring: String, - args: ExportTraitArgs, + callback_interface: bool, }, Struct { self_ident: Ident, @@ -39,17 +29,15 @@ pub(super) enum ExportItem { } impl ExportItem { - pub fn new(item: syn::Item, attr_args: TokenStream) -> syn::Result { + pub fn new(item: syn::Item, args: &ExportAttributeArguments) -> syn::Result { match item { syn::Item::Fn(item) => { - let args: ExportFnArgs = syn::parse(attr_args)?; - let docstring = extract_docstring(&item.attrs)?; - let sig = FnSignature::new_function(item.sig, args.clone(), docstring)?; - Ok(Self::Function { sig, args }) + let sig = FnSignature::new_function(item.sig)?; + Ok(Self::Function { sig }) } - syn::Item::Impl(item) => Self::from_impl(item, attr_args), - syn::Item::Trait(item) => Self::from_trait(item, attr_args), - syn::Item::Struct(item) => Self::from_struct(item, attr_args), + syn::Item::Impl(item) => Self::from_impl(item, args.constructor.is_some()), + syn::Item::Trait(item) => Self::from_trait(item, args.callback_interface.is_some()), + syn::Item::Struct(item) => Self::from_struct(item, args), // FIXME: Support const / static? _ => Err(syn::Error::new( Span::call_site(), @@ -59,8 +47,7 @@ impl ExportItem { } } - pub fn from_impl(item: syn::ItemImpl, attr_args: TokenStream) -> syn::Result { - let args: ExportImplArgs = syn::parse(attr_args)?; + pub fn from_impl(item: syn::ItemImpl, force_constructor: bool) -> syn::Result { if !item.generics.params.is_empty() || item.generics.where_clause.is_some() { return Err(syn::Error::new_spanned( &item.generics, @@ -101,22 +88,14 @@ impl ExportItem { } }; - let docstring = extract_docstring(&impl_fn.attrs)?; let attrs = ExportedImplFnAttributes::new(&impl_fn.attrs)?; - let item = if attrs.constructor { + let item = if force_constructor || attrs.constructor { ImplItem::Constructor(FnSignature::new_constructor( self_ident.clone(), impl_fn.sig, - attrs.args, - docstring, )?) } else { - ImplItem::Method(FnSignature::new_method( - self_ident.clone(), - impl_fn.sig, - attrs.args, - docstring, - )?) + ImplItem::Method(FnSignature::new_method(self_ident.clone(), impl_fn.sig)?) }; Ok(item) @@ -126,15 +105,10 @@ impl ExportItem { Ok(Self::Impl { items, self_ident: self_ident.to_owned(), - args, }) } - fn from_trait(item: syn::ItemTrait, attr_args: TokenStream) -> syn::Result { - let args: ExportTraitArgs = syn::parse(attr_args)?; - let with_foreign = args.callback_interface.is_some() || args.with_foreign.is_some(); - let callback_interface_only = args.callback_interface.is_some(); - + fn from_trait(item: syn::ItemTrait, callback_interface: bool) -> syn::Result { if !item.generics.params.is_empty() || item.generics.where_clause.is_some() { return Err(syn::Error::new_spanned( &item.generics, @@ -143,7 +117,6 @@ impl ExportItem { } let self_ident = item.ident.to_owned(); - let docstring = extract_docstring(&item.attrs)?; let items = item .items .into_iter() @@ -159,7 +132,6 @@ impl ExportItem { } }; - let docstring = extract_docstring(&tim.attrs)?; let attrs = ExportedImplFnAttributes::new(&tim.attrs)?; let item = if attrs.constructor { return Err(syn::Error::new_spanned( @@ -170,9 +142,7 @@ impl ExportItem { ImplItem::Method(FnSignature::new_trait_method( self_ident.clone(), tim.sig, - ExportedImplFnArgs::default(), i as u32, - docstring, )?) }; @@ -183,26 +153,28 @@ impl ExportItem { Ok(Self::Trait { items, self_ident, - with_foreign, - callback_interface_only, - docstring, - args, + callback_interface, }) } - fn from_struct(item: syn::ItemStruct, attr_args: TokenStream) -> syn::Result { - let args: ExportStructArgs = syn::parse(attr_args)?; - let uniffi_traits: Vec = args.traits.into_iter().collect(); - if uniffi_traits.is_empty() { - Err(syn::Error::new(Span::call_site(), - "uniffi::export on a struct must supply a builtin trait name. Did you mean `#[derive(uniffi::Object)]`?" - )) - } else { - Ok(Self::Struct { - self_ident: item.ident, - uniffi_traits, - }) + fn from_struct(item: syn::ItemStruct, args: &ExportAttributeArguments) -> syn::Result { + let mut uniffi_traits = Vec::new(); + if args.trait_debug.is_some() { + uniffi_traits.push(UniffiTraitDiscriminants::Debug); + } + if args.trait_display.is_some() { + uniffi_traits.push(UniffiTraitDiscriminants::Display); + } + if args.trait_hash.is_some() { + uniffi_traits.push(UniffiTraitDiscriminants::Hash); } + if args.trait_eq.is_some() { + uniffi_traits.push(UniffiTraitDiscriminants::Eq); + } + Ok(Self::Struct { + self_ident: item.ident, + uniffi_traits, + }) } } diff --git a/third_party/rust/uniffi_macros/src/export/scaffolding.rs b/third_party/rust/uniffi_macros/src/export/scaffolding.rs index fa7b61decabf..f120ccc880bc 100644 --- a/third_party/rust/uniffi_macros/src/export/scaffolding.rs +++ b/third_party/rust/uniffi_macros/src/export/scaffolding.rs @@ -6,12 +6,12 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; use std::iter; -use super::attributes::AsyncRuntime; -use crate::fnsig::{FnKind, FnSignature}; +use super::attributes::{AsyncRuntime, ExportAttributeArguments}; +use crate::fnsig::{FnKind, FnSignature, NamedArg}; pub(super) fn gen_fn_scaffolding( sig: FnSignature, - ar: &Option, + arguments: &ExportAttributeArguments, udl_mode: bool, ) -> syn::Result { if sig.receiver.is_some() { @@ -21,7 +21,7 @@ pub(super) fn gen_fn_scaffolding( )); } if !sig.is_async { - if let Some(async_runtime) = ar { + if let Some(async_runtime) = &arguments.async_runtime { return Err(syn::Error::new_spanned( async_runtime, "this attribute is only allowed on async functions", @@ -32,7 +32,7 @@ pub(super) fn gen_fn_scaffolding( sig.metadata_items() .unwrap_or_else(syn::Error::into_compile_error) }); - let scaffolding_func = gen_ffi_function(&sig, ar, udl_mode)?; + let scaffolding_func = gen_ffi_function(&sig, arguments, udl_mode)?; Ok(quote! { #scaffolding_func #metadata_items @@ -41,7 +41,7 @@ pub(super) fn gen_fn_scaffolding( pub(super) fn gen_constructor_scaffolding( sig: FnSignature, - ar: &Option, + arguments: &ExportAttributeArguments, udl_mode: bool, ) -> syn::Result { if sig.receiver.is_some() { @@ -50,11 +50,14 @@ pub(super) fn gen_constructor_scaffolding( "constructors must not have a self parameter", )); } + if sig.is_async { + return Err(syn::Error::new(sig.span, "constructors can't be async")); + } let metadata_items = (!udl_mode).then(|| { sig.metadata_items() .unwrap_or_else(syn::Error::into_compile_error) }); - let scaffolding_func = gen_ffi_function(&sig, ar, udl_mode)?; + let scaffolding_func = gen_ffi_function(&sig, arguments, udl_mode)?; Ok(quote! { #scaffolding_func #metadata_items @@ -63,7 +66,7 @@ pub(super) fn gen_constructor_scaffolding( pub(super) fn gen_method_scaffolding( sig: FnSignature, - ar: &Option, + arguments: &ExportAttributeArguments, udl_mode: bool, ) -> syn::Result { let scaffolding_func = if sig.receiver.is_none() { @@ -72,7 +75,7 @@ pub(super) fn gen_method_scaffolding( "associated functions are not currently supported", )); } else { - gen_ffi_function(&sig, ar, udl_mode)? + gen_ffi_function(&sig, arguments, udl_mode)? }; let metadata_items = (!udl_mode).then(|| { @@ -87,37 +90,31 @@ pub(super) fn gen_method_scaffolding( // Pieces of code for the scaffolding function struct ScaffoldingBits { - /// Parameter names for the scaffolding function - param_names: Vec, - /// Parameter types for the scaffolding function - param_types: Vec, + /// Parameters for the scaffolding function + params: Vec, /// Lift closure. See `FnSignature::lift_closure` for an explanation of this. lift_closure: TokenStream, /// Expression to call the Rust function after a successful lift. rust_fn_call: TokenStream, - /// Convert the result of `rust_fn_call`, stored in a variable named `uniffi_result` into its final value. - /// This is used to do things like error conversion / Arc wrapping - convert_result: TokenStream, } impl ScaffoldingBits { fn new_for_function(sig: &FnSignature, udl_mode: bool) -> Self { let ident = &sig.ident; + let params: Vec<_> = sig.args.iter().map(NamedArg::scaffolding_param).collect(); let call_params = sig.rust_call_params(false); let rust_fn_call = quote! { #ident(#call_params) }; // UDL mode adds an extra conversion (#1749) - let convert_result = if udl_mode && sig.looks_like_result { - quote! { uniffi_result.map_err(::std::convert::Into::into) } + let rust_fn_call = if udl_mode && sig.looks_like_result { + quote! { #rust_fn_call.map_err(::std::convert::Into::into) } } else { - quote! { uniffi_result } + rust_fn_call }; Self { - param_names: sig.scaffolding_param_names().collect(), - param_types: sig.scaffolding_param_types().collect(), + params, lift_closure: sig.lift_closure(None), rust_fn_call, - convert_result, } } @@ -128,32 +125,20 @@ impl ScaffoldingBits { udl_mode: bool, ) -> Self { let ident = &sig.ident; - let lift_impl = if is_trait { + let ffi_converter = if is_trait { quote! { - <::std::sync::Arc as ::uniffi::Lift> + <::std::sync::Arc as ::uniffi::FfiConverter> } } else { quote! { - <::std::sync::Arc<#self_ident> as ::uniffi::Lift> + <::std::sync::Arc<#self_ident> as ::uniffi::FfiConverter> } }; - let try_lift_self = if is_trait { - // For trait interfaces we need to special case this. Trait interfaces normally lift - // foreign trait impl pointers. However, for a method call, we want to lift a Rust - // pointer. - quote! { - { - let boxed_foreign_arc = unsafe { Box::from_raw(uniffi_self_lowered as *mut ::std::sync::Arc) }; - // Take a clone for our own use. - Ok(*boxed_foreign_arc) - } - } - } else { - quote! { #lift_impl::try_lift(uniffi_self_lowered) } - }; - + let params: Vec<_> = iter::once(quote! { uniffi_self_lowered: #ffi_converter::FfiType }) + .chain(sig.scaffolding_params()) + .collect(); let lift_closure = sig.lift_closure(Some(quote! { - match #try_lift_self { + match #ffi_converter::try_lift(uniffi_self_lowered) { Ok(v) => v, Err(e) => return Err(("self", e)) } @@ -161,45 +146,38 @@ impl ScaffoldingBits { let call_params = sig.rust_call_params(true); let rust_fn_call = quote! { uniffi_args.0.#ident(#call_params) }; // UDL mode adds an extra conversion (#1749) - let convert_result = if udl_mode && sig.looks_like_result { - quote! { uniffi_result .map_err(::std::convert::Into::into) } + let rust_fn_call = if udl_mode && sig.looks_like_result { + quote! { #rust_fn_call.map_err(::std::convert::Into::into) } } else { - quote! { uniffi_result } + rust_fn_call }; Self { - param_names: iter::once(quote! { uniffi_self_lowered }) - .chain(sig.scaffolding_param_names()) - .collect(), - param_types: iter::once(quote! { #lift_impl::FfiType }) - .chain(sig.scaffolding_param_types()) - .collect(), + params, lift_closure, rust_fn_call, - convert_result, } } fn new_for_constructor(sig: &FnSignature, self_ident: &Ident, udl_mode: bool) -> Self { let ident = &sig.ident; + let params: Vec<_> = sig.args.iter().map(NamedArg::scaffolding_param).collect(); let call_params = sig.rust_call_params(false); let rust_fn_call = quote! { #self_ident::#ident(#call_params) }; // UDL mode adds extra conversions (#1749) - let convert_result = match (udl_mode, sig.looks_like_result) { + let rust_fn_call = match (udl_mode, sig.looks_like_result) { // For UDL - (true, false) => quote! { ::std::sync::Arc::new(uniffi_result) }, + (true, false) => quote! { ::std::sync::Arc::new(#rust_fn_call) }, (true, true) => { - quote! { uniffi_result.map(::std::sync::Arc::new).map_err(::std::convert::Into::into) } + quote! { #rust_fn_call.map(::std::sync::Arc::new).map_err(::std::convert::Into::into) } } - (false, _) => quote! { uniffi_result }, + (false, _) => rust_fn_call, }; Self { - param_names: sig.scaffolding_param_names().collect(), - param_types: sig.scaffolding_param_types().collect(), + params, lift_closure: sig.lift_closure(None), rust_fn_call, - convert_result, } } } @@ -210,15 +188,13 @@ impl ScaffoldingBits { /// `rust_fn` is the Rust function to call. pub(super) fn gen_ffi_function( sig: &FnSignature, - ar: &Option, + arguments: &ExportAttributeArguments, udl_mode: bool, ) -> syn::Result { let ScaffoldingBits { - param_names, - param_types, + params, lift_closure, rust_fn_call, - convert_result, } = match &sig.kind { FnKind::Function => ScaffoldingBits::new_for_function(sig, udl_mode), FnKind::Method { self_ident } => { @@ -240,15 +216,14 @@ pub(super) fn gen_ffi_function( let ffi_ident = sig.scaffolding_fn_ident()?; let name = &sig.name; - let return_ty = &sig.return_ty; - let return_impl = &sig.lower_return_impl(); + let return_impl = &sig.return_impl(); Ok(if !sig.is_async { quote! { #[doc(hidden)] #[no_mangle] #vis extern "C" fn #ffi_ident( - #(#param_names: #param_types,)* + #(#params,)* call_status: &mut ::uniffi::RustCallStatus, ) -> #return_impl::ReturnType { ::uniffi::deps::log::debug!(#name); @@ -256,10 +231,7 @@ pub(super) fn gen_ffi_function( ::uniffi::rust_call(call_status, || { #return_impl::lower_return( match uniffi_lift_args() { - Ok(uniffi_args) => { - let uniffi_result = #rust_fn_call; - #convert_result - } + Ok(uniffi_args) => #rust_fn_call, Err((arg_name, anyhow_error)) => { #return_impl::handle_failed_lift(arg_name, anyhow_error) }, @@ -270,28 +242,25 @@ pub(super) fn gen_ffi_function( } } else { let mut future_expr = rust_fn_call; - if matches!(ar, Some(AsyncRuntime::Tokio(_))) { + if matches!(arguments.async_runtime, Some(AsyncRuntime::Tokio(_))) { future_expr = quote! { ::uniffi::deps::async_compat::Compat::new(#future_expr) } } quote! { #[doc(hidden)] #[no_mangle] - pub extern "C" fn #ffi_ident(#(#param_names: #param_types,)*) -> ::uniffi::Handle { + pub extern "C" fn #ffi_ident(#(#params,)*) -> ::uniffi::RustFutureHandle { ::uniffi::deps::log::debug!(#name); let uniffi_lift_args = #lift_closure; match uniffi_lift_args() { Ok(uniffi_args) => { - ::uniffi::rust_future_new::<_, #return_ty, _>( - async move { - let uniffi_result = #future_expr.await; - #convert_result - }, + ::uniffi::rust_future_new( + async move { #future_expr.await }, crate::UniFfiTag ) }, Err((arg_name, anyhow_error)) => { - ::uniffi::rust_future_new::<_, #return_ty, _>( + ::uniffi::rust_future_new( async move { #return_impl::handle_failed_lift(arg_name, anyhow_error) }, diff --git a/third_party/rust/uniffi_macros/src/export/trait_interface.rs b/third_party/rust/uniffi_macros/src/export/trait_interface.rs deleted file mode 100644 index 83587ae386c3..000000000000 --- a/third_party/rust/uniffi_macros/src/export/trait_interface.rs +++ /dev/null @@ -1,183 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use proc_macro2::{Ident, Span, TokenStream}; -use quote::{quote, quote_spanned}; - -use uniffi_meta::ObjectImpl; - -use crate::{ - export::{ - attributes::ExportTraitArgs, callback_interface, gen_method_scaffolding, item::ImplItem, - }, - object::interface_meta_static_var, - util::{ident_to_string, tagged_impl_header}, -}; - -pub(super) fn gen_trait_scaffolding( - mod_path: &str, - args: ExportTraitArgs, - self_ident: Ident, - items: Vec, - udl_mode: bool, - with_foreign: bool, - docstring: String, -) -> syn::Result { - if let Some(rt) = args.async_runtime { - return Err(syn::Error::new_spanned(rt, "not supported for traits")); - } - let trait_name = ident_to_string(&self_ident); - let trait_impl = with_foreign.then(|| { - callback_interface::trait_impl(mod_path, &self_ident, &items) - .unwrap_or_else(|e| e.into_compile_error()) - }); - - let clone_fn_ident = Ident::new( - &uniffi_meta::clone_fn_symbol_name(mod_path, &trait_name), - Span::call_site(), - ); - let free_fn_ident = Ident::new( - &uniffi_meta::free_fn_symbol_name(mod_path, &trait_name), - Span::call_site(), - ); - - let helper_fn_tokens = quote! { - #[doc(hidden)] - #[no_mangle] - /// Clone a pointer to this object type - /// - /// Safety: Only pass pointers returned by a UniFFI call. Do not pass pointers that were - /// passed to the free function. - pub unsafe extern "C" fn #clone_fn_ident( - ptr: *const ::std::ffi::c_void, - call_status: &mut ::uniffi::RustCallStatus - ) -> *const ::std::ffi::c_void { - uniffi::rust_call(call_status, || { - let ptr = ptr as *mut std::sync::Arc; - let arc = unsafe { ::std::sync::Arc::clone(&*ptr) }; - Ok(::std::boxed::Box::into_raw(::std::boxed::Box::new(arc)) as *const ::std::ffi::c_void) - }) - } - - #[doc(hidden)] - #[no_mangle] - /// Free a pointer to this object type - /// - /// Safety: Only pass pointers returned by a UniFFI call. Do not pass pointers that were - /// passed to the free function. - /// - /// Note: clippy doesn't complain about this being unsafe, but it definitely is since it - /// calls `Box::from_raw`. - pub unsafe extern "C" fn #free_fn_ident( - ptr: *const ::std::ffi::c_void, - call_status: &mut ::uniffi::RustCallStatus - ) { - uniffi::rust_call(call_status, || { - assert!(!ptr.is_null()); - drop(unsafe { ::std::boxed::Box::from_raw(ptr as *mut std::sync::Arc) }); - Ok(()) - }); - } - }; - - let impl_tokens: TokenStream = items - .into_iter() - .map(|item| match item { - ImplItem::Method(sig) => gen_method_scaffolding(sig, &None, udl_mode), - _ => unreachable!("traits have no constructors"), - }) - .collect::>()?; - - let meta_static_var = (!udl_mode).then(|| { - let imp = if with_foreign { - ObjectImpl::CallbackTrait - } else { - ObjectImpl::Trait - }; - interface_meta_static_var(&self_ident, imp, mod_path, docstring) - .unwrap_or_else(syn::Error::into_compile_error) - }); - let ffi_converter_tokens = ffi_converter(mod_path, &self_ident, udl_mode, with_foreign); - - Ok(quote_spanned! { self_ident.span() => - #meta_static_var - #helper_fn_tokens - #trait_impl - #impl_tokens - #ffi_converter_tokens - }) -} - -pub(crate) fn ffi_converter( - mod_path: &str, - trait_ident: &Ident, - udl_mode: bool, - with_foreign: bool, -) -> TokenStream { - let impl_spec = tagged_impl_header("FfiConverterArc", "e! { dyn #trait_ident }, udl_mode); - let lift_ref_impl_spec = tagged_impl_header("LiftRef", "e! { dyn #trait_ident }, udl_mode); - let trait_name = ident_to_string(trait_ident); - let try_lift = if with_foreign { - let trait_impl_ident = callback_interface::trait_impl_ident(&trait_name); - quote! { - fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result<::std::sync::Arc> { - Ok(::std::sync::Arc::new(<#trait_impl_ident>::new(v as u64))) - } - } - } else { - quote! { - fn try_lift(v: Self::FfiType) -> ::uniffi::deps::anyhow::Result<::std::sync::Arc> { - unsafe { - Ok(*::std::boxed::Box::from_raw(v as *mut ::std::sync::Arc)) - } - } - } - }; - let metadata_code = if with_foreign { - quote! { ::uniffi::metadata::codes::TYPE_CALLBACK_TRAIT_INTERFACE } - } else { - quote! { ::uniffi::metadata::codes::TYPE_TRAIT_INTERFACE } - }; - - quote! { - // All traits must be `Sync + Send`. The generated scaffolding will fail to compile - // if they are not, but unfortunately it fails with an unactionably obscure error message. - // By asserting the requirement explicitly, we help Rust produce a more scrutable error message - // and thus help the user debug why the requirement isn't being met. - uniffi::deps::static_assertions::assert_impl_all!(dyn #trait_ident: ::core::marker::Sync, ::core::marker::Send); - - unsafe #impl_spec { - type FfiType = *const ::std::os::raw::c_void; - - fn lower(obj: ::std::sync::Arc) -> Self::FfiType { - ::std::boxed::Box::into_raw(::std::boxed::Box::new(obj)) as *const ::std::os::raw::c_void - } - - #try_lift - - fn write(obj: ::std::sync::Arc, buf: &mut Vec) { - ::uniffi::deps::static_assertions::const_assert!(::std::mem::size_of::<*const ::std::ffi::c_void>() <= 8); - ::uniffi::deps::bytes::BufMut::put_u64( - buf, - >::lower(obj) as u64, - ); - } - - fn try_read(buf: &mut &[u8]) -> ::uniffi::Result<::std::sync::Arc> { - ::uniffi::deps::static_assertions::const_assert!(::std::mem::size_of::<*const ::std::ffi::c_void>() <= 8); - ::uniffi::check_remaining(buf, 8)?; - >::try_lift( - ::uniffi::deps::bytes::Buf::get_u64(buf) as Self::FfiType) - } - - const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(#metadata_code) - .concat_str(#mod_path) - .concat_str(#trait_name); - } - - unsafe #lift_ref_impl_spec { - type LiftType = ::std::sync::Arc; - } - } -} diff --git a/third_party/rust/uniffi_macros/src/export/utrait.rs b/third_party/rust/uniffi_macros/src/export/utrait.rs index 9007ae2c56ba..3db09ea2b7d3 100644 --- a/third_party/rust/uniffi_macros/src/export/utrait.rs +++ b/third_party/rust/uniffi_macros/src/export/utrait.rs @@ -6,10 +6,8 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; use syn::ext::IdentExt; -use super::gen_ffi_function; -use crate::export::ExportedImplFnArgs; +use super::{attributes::ExportAttributeArguments, gen_ffi_function}; use crate::fnsig::FnSignature; -use crate::util::extract_docstring; use uniffi_meta::UniffiTraitDiscriminants; pub(crate) fn expand_uniffi_trait_export( @@ -159,25 +157,12 @@ fn process_uniffi_trait_method( unreachable!() }; - let docstring = extract_docstring(&item.attrs)?; - let ffi_func = gen_ffi_function( - &FnSignature::new_method( - self_ident.clone(), - item.sig.clone(), - ExportedImplFnArgs::default(), - docstring.clone(), - )?, - &None, + &FnSignature::new_method(self_ident.clone(), item.sig.clone())?, + &ExportAttributeArguments::default(), udl_mode, )?; // metadata for the method, which will be packed inside metadata for the trait. - let method_meta = FnSignature::new_method( - self_ident.clone(), - item.sig, - ExportedImplFnArgs::default(), - docstring, - )? - .metadata_expr()?; + let method_meta = FnSignature::new_method(self_ident.clone(), item.sig)?.metadata_expr()?; Ok((ffi_func, method_meta)) } diff --git a/third_party/rust/uniffi_macros/src/fnsig.rs b/third_party/rust/uniffi_macros/src/fnsig.rs index 9c591252077d..69b6529d1e05 100644 --- a/third_party/rust/uniffi_macros/src/fnsig.rs +++ b/third_party/rust/uniffi_macros/src/fnsig.rs @@ -2,10 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use crate::{ - default::{default_value_metadata_calls, DefaultValue}, - export::{DefaultMap, ExportFnArgs, ExportedImplFnArgs}, - util::{create_metadata_items, ident_to_string, mod_path, try_metadata_value_from_usize}, +use crate::util::{ + create_metadata_items, ident_to_string, mod_path, try_metadata_value_from_usize, }; use proc_macro2::{Span, TokenStream}; use quote::quote; @@ -15,9 +13,7 @@ pub(crate) struct FnSignature { pub kind: FnKind, pub span: Span, pub mod_path: String, - // The identifier of the Rust function. pub ident: Ident, - // The foreign name for this function, usually == ident. pub name: String, pub is_async: bool, pub receiver: Option, @@ -27,71 +23,30 @@ pub(crate) struct FnSignature { // Only use this in UDL mode. // In general, it's not reliable because it fails for type aliases. pub looks_like_result: bool, - pub docstring: String, } impl FnSignature { - pub(crate) fn new_function( - sig: syn::Signature, - args: ExportFnArgs, - docstring: String, - ) -> syn::Result { - Self::new(FnKind::Function, sig, args.name, args.defaults, docstring) + pub(crate) fn new_function(sig: syn::Signature) -> syn::Result { + Self::new(FnKind::Function, sig) } - pub(crate) fn new_method( - self_ident: Ident, - sig: syn::Signature, - args: ExportedImplFnArgs, - docstring: String, - ) -> syn::Result { - Self::new( - FnKind::Method { self_ident }, - sig, - args.name, - args.defaults, - docstring, - ) + pub(crate) fn new_method(self_ident: Ident, sig: syn::Signature) -> syn::Result { + Self::new(FnKind::Method { self_ident }, sig) } - pub(crate) fn new_constructor( - self_ident: Ident, - sig: syn::Signature, - args: ExportedImplFnArgs, - docstring: String, - ) -> syn::Result { - Self::new( - FnKind::Constructor { self_ident }, - sig, - args.name, - args.defaults, - docstring, - ) + pub(crate) fn new_constructor(self_ident: Ident, sig: syn::Signature) -> syn::Result { + Self::new(FnKind::Constructor { self_ident }, sig) } pub(crate) fn new_trait_method( self_ident: Ident, sig: syn::Signature, - args: ExportedImplFnArgs, index: u32, - docstring: String, ) -> syn::Result { - Self::new( - FnKind::TraitMethod { self_ident, index }, - sig, - args.name, - args.defaults, - docstring, - ) + Self::new(FnKind::TraitMethod { self_ident, index }, sig) } - pub(crate) fn new( - kind: FnKind, - sig: syn::Signature, - name: Option, - mut defaults: DefaultMap, - docstring: String, - ) -> syn::Result { + pub(crate) fn new(kind: FnKind, sig: syn::Signature) -> syn::Result { let span = sig.span(); let ident = sig.ident; let looks_like_result = looks_like_result(&sig.output); @@ -101,11 +56,14 @@ impl FnSignature { }; let is_async = sig.asyncness.is_some(); - let mut input_iter = sig - .inputs - .into_iter() - .map(|a| Arg::new(a, &mut defaults)) - .peekable(); + if is_async && matches!(kind, FnKind::Constructor { .. }) { + return Err(syn::Error::new( + span, + "Async constructors are not supported", + )); + } + + let mut input_iter = sig.inputs.into_iter().map(Arg::try_from).peekable(); let receiver = input_iter .next_if(|a| matches!(a, Ok(a) if a.is_receiver())) @@ -126,43 +84,29 @@ impl FnSignature { }) }) .collect::>>()?; - - if let Some(ident) = defaults.idents().first() { - return Err(syn::Error::new( - ident.span(), - format!("Unknown default argument: {}", ident), - )); - } + let mod_path = mod_path()?; Ok(Self { kind, span, - mod_path: mod_path()?, - name: name.unwrap_or_else(|| ident_to_string(&ident)), + mod_path, + name: ident_to_string(&ident), ident, is_async, receiver, args, return_ty: output, looks_like_result, - docstring, }) } - pub fn lower_return_impl(&self) -> TokenStream { + pub fn return_impl(&self) -> TokenStream { let return_ty = &self.return_ty; quote! { <#return_ty as ::uniffi::LowerReturn> } } - pub fn lift_return_impl(&self) -> TokenStream { - let return_ty = &self.return_ty; - quote! { - <#return_ty as ::uniffi::LiftReturn> - } - } - /// Generate a closure that tries to lift all arguments into a tuple. /// /// The closure moves all scaffolding arguments into itself and returns: @@ -207,6 +151,14 @@ impl FnSignature { quote! { #(#args),* } } + /// Write expressions for each of our arguments + pub fn write_exprs<'a>( + &'a self, + buf_ident: &'a Ident, + ) -> impl Iterator + 'a { + self.args.iter().map(|a| a.write_expr(buf_ident)) + } + /// Parameters expressions for each of our arguments pub fn params(&self) -> impl Iterator + '_ { self.args.iter().map(NamedArg::param) @@ -230,18 +182,8 @@ impl FnSignature { } /// Scaffolding parameters expressions for each of our arguments - pub fn scaffolding_param_names(&self) -> impl Iterator + '_ { - self.args.iter().map(|a| { - let ident = &a.ident; - quote! { #ident } - }) - } - - pub fn scaffolding_param_types(&self) -> impl Iterator + '_ { - self.args.iter().map(|a| { - let lift_impl = a.lift_impl(); - quote! { #lift_impl::FfiType } - }) + pub fn scaffolding_params(&self) -> impl Iterator + '_ { + self.args.iter().map(NamedArg::scaffolding_param) } /// Generate metadata items for this function @@ -251,7 +193,6 @@ impl FnSignature { return_ty, is_async, mod_path, - docstring, .. } = &self; let args_len = try_metadata_value_from_usize( @@ -260,11 +201,7 @@ impl FnSignature { self.args.len(), "UniFFI limits functions to 256 arguments", )?; - let arg_metadata_calls = self - .args - .iter() - .map(NamedArg::arg_metadata) - .collect::>>()?; + let arg_metadata_calls = self.args.iter().map(NamedArg::arg_metadata); match &self.kind { FnKind::Function => Ok(quote! { @@ -275,7 +212,6 @@ impl FnSignature { .concat_value(#args_len) #(#arg_metadata_calls)* .concat(<#return_ty as ::uniffi::LowerReturn>::TYPE_ID_META) - .concat_long_str(#docstring) }), FnKind::Method { self_ident } => { @@ -289,7 +225,6 @@ impl FnSignature { .concat_value(#args_len) #(#arg_metadata_calls)* .concat(<#return_ty as ::uniffi::LowerReturn>::TYPE_ID_META) - .concat_long_str(#docstring) }) } @@ -305,7 +240,6 @@ impl FnSignature { .concat_value(#args_len) #(#arg_metadata_calls)* .concat(<#return_ty as ::uniffi::LowerReturn>::TYPE_ID_META) - .concat_long_str(#docstring) }) } @@ -316,11 +250,9 @@ impl FnSignature { .concat_str(#mod_path) .concat_str(#object_name) .concat_str(#name) - .concat_bool(#is_async) .concat_value(#args_len) #(#arg_metadata_calls)* .concat(<#return_ty as ::uniffi::LowerReturn>::TYPE_ID_META) - .concat_long_str(#docstring) }) } } @@ -368,69 +300,6 @@ impl FnSignature { } } - /// Generate metadata items for callback interfaces - /// - /// Unfortunately, most of this is duplicate code from [Self::metadata_items] and - /// [Self::metadata_expr]. However, one issue with that code is that it needs to assume if the - /// arguments are being lifted vs lowered in order to get TYPE_ID_META. That code uses - /// `::TYPE_ID_META` for arguments and `::TYPE_ID_META` for - /// return types, which works for accidental/historical reasons. - /// - /// The one exception is callback interfaces (#1947), which are handled by this method. - /// - /// TODO: fix the metadata system so that this is not needed. - pub(crate) fn metadata_items_for_callback_interface(&self) -> syn::Result { - let Self { - name, - return_ty, - is_async, - mod_path, - docstring, - .. - } = &self; - match &self.kind { - FnKind::TraitMethod { - self_ident, index, .. - } => { - let object_name = ident_to_string(self_ident); - let args_len = try_metadata_value_from_usize( - // Use param_lifts to calculate this instead of sig.inputs to avoid counting any self - // params - self.args.len(), - "UniFFI limits functions to 256 arguments", - )?; - let arg_metadata_calls = self - .args - .iter() - .map(NamedArg::arg_metadata) - .collect::>>()?; - let metadata_expr = quote! { - ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TRAIT_METHOD) - .concat_str(#mod_path) - .concat_str(#object_name) - .concat_u32(#index) - .concat_str(#name) - .concat_bool(#is_async) - .concat_value(#args_len) - #(#arg_metadata_calls)* - .concat(<#return_ty as ::uniffi::LiftReturn>::TYPE_ID_META) - .concat_long_str(#docstring) - }; - Ok(create_metadata_items( - "method", - &format!("{object_name}_{name}"), - metadata_expr, - Some(self.checksum_symbol_name()), - )) - } - - // This should never happen and indicates an error in the internal code - _ => panic!( - "metadata_items_for_callback_interface can only be called with `TraitMethod` sigs" - ), - } - } - pub(crate) fn checksum_symbol_name(&self) -> String { let name = &self.name; match &self.kind { @@ -462,11 +331,19 @@ pub(crate) enum ArgKind { } impl Arg { - fn new(syn_arg: FnArg, defaults: &mut DefaultMap) -> syn::Result { + pub(crate) fn is_receiver(&self) -> bool { + matches!(self.kind, ArgKind::Receiver(_)) + } +} + +impl TryFrom for Arg { + type Error = syn::Error; + + fn try_from(syn_arg: FnArg) -> syn::Result { let span = syn_arg.span(); let kind = match syn_arg { FnArg::Typed(p) => match *p.pat { - Pat::Ident(i) => Ok(ArgKind::Named(NamedArg::new(i.ident, &p.ty, defaults)?)), + Pat::Ident(i) => Ok(ArgKind::Named(NamedArg::new(i.ident, &p.ty))), _ => Err(syn::Error::new_spanned(p, "Argument name missing")), }, FnArg::Receiver(receiver) => Ok(ArgKind::Receiver(ReceiverArg::from(receiver))), @@ -474,10 +351,6 @@ impl Arg { Ok(Self { span, kind }) } - - pub(crate) fn is_receiver(&self) -> bool { - matches!(self.kind, ArgKind::Receiver(_)) - } } pub(crate) enum ReceiverArg { @@ -506,30 +379,27 @@ pub(crate) struct NamedArg { pub(crate) name: String, pub(crate) ty: TokenStream, pub(crate) ref_type: Option, - pub(crate) default: Option, } impl NamedArg { - pub(crate) fn new(ident: Ident, ty: &Type, defaults: &mut DefaultMap) -> syn::Result { - Ok(match ty { + pub(crate) fn new(ident: Ident, ty: &Type) -> Self { + match ty { Type::Reference(r) => { let inner = &r.elem; Self { name: ident_to_string(&ident), + ident, ty: quote! { <#inner as ::uniffi::LiftRef>::LiftType }, ref_type: Some(*inner.clone()), - default: defaults.remove(&ident), - ident, } } _ => Self { name: ident_to_string(&ident), + ident, ty: quote! { #ty }, ref_type: None, - default: defaults.remove(&ident), - ident, }, - }) + } } pub(crate) fn lift_impl(&self) -> TokenStream { @@ -549,15 +419,27 @@ impl NamedArg { quote! { #ident: #ty } } - pub(crate) fn arg_metadata(&self) -> syn::Result { + /// Generate the scaffolding parameter for this Arg + pub(crate) fn scaffolding_param(&self) -> TokenStream { + let ident = &self.ident; + let lift_impl = self.lift_impl(); + quote! { #ident: #lift_impl::FfiType } + } + + /// Generate the expression to write the scaffolding parameter for this arg + pub(crate) fn write_expr(&self, buf_ident: &Ident) -> TokenStream { + let ident = &self.ident; + let lower_impl = self.lower_impl(); + quote! { #lower_impl::write(#ident, &mut #buf_ident) } + } + + pub(crate) fn arg_metadata(&self) -> TokenStream { let name = &self.name; let lift_impl = self.lift_impl(); - let default_calls = default_value_metadata_calls(&self.default)?; - Ok(quote! { + quote! { .concat_str(#name) .concat(#lift_impl::TYPE_ID_META) - #default_calls - }) + } } } diff --git a/third_party/rust/uniffi_macros/src/lib.rs b/third_party/rust/uniffi_macros/src/lib.rs index 929400c885f1..4cffddfa0eac 100644 --- a/third_party/rust/uniffi_macros/src/lib.rs +++ b/third_party/rust/uniffi_macros/src/lib.rs @@ -5,8 +5,10 @@ #![warn(rust_2018_idioms, unused_qualifications)] //! Macros for `uniffi`. +//! +//! Currently this is just for easily generating integration tests, but maybe +//! we'll put some other code-annotation helper macros in here at some point. -#[cfg(feature = "trybuild")] use camino::Utf8Path; use proc_macro::TokenStream; use quote::quote; @@ -16,7 +18,6 @@ use syn::{ }; mod custom; -mod default; mod enum_; mod error; mod export; @@ -32,6 +33,20 @@ use self::{ record::expand_record, }; +struct IdentPair { + lhs: Ident, + rhs: Ident, +} + +impl Parse for IdentPair { + fn parse(input: ParseStream<'_>) -> syn::Result { + let lhs = input.parse()?; + input.parse::()?; + let rhs = input.parse()?; + Ok(Self { lhs, rhs }) + } +} + struct CustomTypeInfo { ident: Ident, builtin: Path, @@ -92,8 +107,9 @@ fn do_export(attr_args: TokenStream, input: TokenStream, udl_mode: bool) -> Toke let copied_input = (!udl_mode).then(|| proc_macro2::TokenStream::from(input.clone())); let gen_output = || { + let args = syn::parse(attr_args)?; let item = syn::parse(input)?; - expand_export(item, attr_args, udl_mode) + expand_export(item, args, udl_mode) }; let output = gen_output().unwrap_or_else(syn::Error::into_compile_error); @@ -113,7 +129,7 @@ pub fn derive_record(input: TokenStream) -> TokenStream { #[proc_macro_derive(Enum)] pub fn derive_enum(input: TokenStream) -> TokenStream { - expand_enum(parse_macro_input!(input), None, false) + expand_enum(parse_macro_input!(input), false) .unwrap_or_else(syn::Error::into_compile_error) .into() } @@ -209,14 +225,10 @@ pub fn derive_record_for_udl(_attrs: TokenStream, input: TokenStream) -> TokenSt #[doc(hidden)] #[proc_macro_attribute] -pub fn derive_enum_for_udl(attrs: TokenStream, input: TokenStream) -> TokenStream { - expand_enum( - syn::parse_macro_input!(input), - Some(syn::parse_macro_input!(attrs)), - true, - ) - .unwrap_or_else(syn::Error::into_compile_error) - .into() +pub fn derive_enum_for_udl(_attrs: TokenStream, input: TokenStream) -> TokenStream { + expand_enum(syn::parse_macro_input!(input), true) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } #[doc(hidden)] @@ -245,6 +257,22 @@ pub fn export_for_udl(attrs: TokenStream, input: TokenStream) -> TokenStream { do_export(attrs, input, true) } +/// Generate various support elements, including the FfiConverter implementation, +/// for a trait interface for the scaffolding code +#[doc(hidden)] +#[proc_macro] +pub fn expand_trait_interface_support(tokens: TokenStream) -> TokenStream { + export::ffi_converter_trait_impl(&syn::parse_macro_input!(tokens), true).into() +} + +/// Generate the FfiConverter implementation for an trait interface for the scaffolding code +#[doc(hidden)] +#[proc_macro] +pub fn scaffolding_ffi_converter_callback_interface(tokens: TokenStream) -> TokenStream { + let input: IdentPair = syn::parse_macro_input!(tokens); + export::ffi_converter_callback_interface_impl(&input.lhs, &input.rhs, true).into() +} + /// A helper macro to include generated component scaffolding. /// /// This is a simple convenience macro to include the UniFFI component @@ -345,7 +373,6 @@ pub fn use_udl_object(tokens: TokenStream) -> TokenStream { /// uniffi_macros::generate_and_include_scaffolding!("path/to/my/interface.udl"); /// ``` #[proc_macro] -#[cfg(feature = "trybuild")] pub fn generate_and_include_scaffolding(udl_file: TokenStream) -> TokenStream { let udl_file = syn::parse_macro_input!(udl_file as LitStr); let udl_file_string = udl_file.value(); @@ -369,25 +396,15 @@ pub fn generate_and_include_scaffolding(udl_file: TokenStream) -> TokenStream { }.into() } -/// An attribute for constructors. -/// -/// Constructors are in `impl` blocks which have a `#[uniffi::export]` attribute, +/// A dummy macro that does nothing. /// /// This exists so `#[uniffi::export]` can emit its input verbatim without -/// causing unexpected errors in the entire exported block. -/// This happens very often when the proc-macro is run on an incomplete -/// input by rust-analyzer while the developer is typing. +/// causing unexpected errors, plus some extra code in case everything is okay. /// -/// So much better to do nothing here then let the impl block find the attribute. +/// It is important for `#[uniffi::export]` to not raise unexpected errors if it +/// fails to parse the input as this happens very often when the proc-macro is +/// run on an incomplete input by rust-analyzer while the developer is typing. #[proc_macro_attribute] pub fn constructor(_attrs: TokenStream, input: TokenStream) -> TokenStream { input } - -/// An attribute for methods. -/// -/// Everything above applies here too. -#[proc_macro_attribute] -pub fn method(_attrs: TokenStream, input: TokenStream) -> TokenStream { - input -} diff --git a/third_party/rust/uniffi_macros/src/object.rs b/third_party/rust/uniffi_macros/src/object.rs index 6bcc07a14e07..573a1eaadd7c 100644 --- a/third_party/rust/uniffi_macros/src/object.rs +++ b/third_party/rust/uniffi_macros/src/object.rs @@ -1,27 +1,17 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; use syn::DeriveInput; +use uniffi_meta::free_fn_symbol_name; -use crate::util::{ - create_metadata_items, extract_docstring, ident_to_string, mod_path, tagged_impl_header, -}; -use uniffi_meta::ObjectImpl; +use crate::util::{create_metadata_items, ident_to_string, mod_path, tagged_impl_header}; pub fn expand_object(input: DeriveInput, udl_mode: bool) -> syn::Result { let module_path = mod_path()?; let ident = &input.ident; - let docstring = extract_docstring(&input.attrs)?; let name = ident_to_string(ident); - let clone_fn_ident = Ident::new( - &uniffi_meta::clone_fn_symbol_name(&module_path, &name), - Span::call_site(), - ); - let free_fn_ident = Ident::new( - &uniffi_meta::free_fn_symbol_name(&module_path, &name), - Span::call_site(), - ); + let free_fn_ident = Ident::new(&free_fn_symbol_name(&module_path, &name), Span::call_site()); let meta_static_var = (!udl_mode).then(|| { - interface_meta_static_var(ident, ObjectImpl::Struct, &module_path, docstring) + interface_meta_static_var(ident, false, &module_path) .unwrap_or_else(syn::Error::into_compile_error) }); let interface_impl = interface_impl(ident, udl_mode); @@ -29,19 +19,7 @@ pub fn expand_object(input: DeriveInput, udl_mode: bool) -> syn::Result *const ::std::ffi::c_void { - uniffi::rust_call(call_status, || { - unsafe { ::std::sync::Arc::increment_strong_count(ptr) }; - Ok(ptr) - }) - } - - #[doc(hidden)] - #[no_mangle] - pub unsafe extern "C" fn #free_fn_ident( + pub extern "C" fn #free_fn_ident( ptr: *const ::std::ffi::c_void, call_status: &mut ::uniffi::RustCallStatus ) { @@ -63,7 +41,6 @@ pub fn expand_object(input: DeriveInput, udl_mode: bool) -> syn::Result TokenStream { let name = ident_to_string(ident); let impl_spec = tagged_impl_header("FfiConverterArc", ident, udl_mode); - let lower_return_impl_spec = tagged_impl_header("LowerReturn", ident, udl_mode); let lift_ref_impl_spec = tagged_impl_header("LiftRef", ident, udl_mode); let mod_path = match mod_path() { Ok(p) => p, @@ -75,7 +52,7 @@ pub(crate) fn interface_impl(ident: &Ident, udl_mode: bool) -> TokenStream { // if they are not, but unfortunately it fails with an unactionably obscure error message. // By asserting the requirement explicitly, we help Rust produce a more scrutable error message // and thus help the user debug why the requirement isn't being met. - uniffi::deps::static_assertions::assert_impl_all!(#ident: ::core::marker::Sync, ::core::marker::Send); + uniffi::deps::static_assertions::assert_impl_all!(#ident: Sync, Send); #[doc(hidden)] #[automatically_derived] @@ -101,10 +78,17 @@ pub(crate) fn interface_impl(ident: &Ident, udl_mode: bool) -> TokenStream { ::std::sync::Arc::into_raw(obj) as Self::FfiType } - /// When lifting, we receive an owned `Arc` that the foreign language code cloned. + /// When lifting, we receive a "borrow" of the `Arc` that is owned by + /// the foreign-language code, and make a clone of it for our own use. + /// + /// Safety: the provided value must be a pointer previously obtained by calling + /// the `lower()` or `write()` method of this impl. fn try_lift(v: Self::FfiType) -> ::uniffi::Result<::std::sync::Arc> { let v = v as *const #ident; - Ok(unsafe { ::std::sync::Arc::::from_raw(v) }) + // We musn't drop the `Arc` that is owned by the foreign-language code. + let foreign_arc = ::std::mem::ManuallyDrop::new(unsafe { ::std::sync::Arc::::from_raw(v) }); + // Take a clone for our own use. + Ok(::std::sync::Arc::clone(&*foreign_arc)) } /// When writing as a field of a complex structure, make a clone and transfer ownership @@ -133,17 +117,8 @@ pub(crate) fn interface_impl(ident: &Ident, udl_mode: bool) -> TokenStream { const TYPE_ID_META: ::uniffi::MetadataBuffer = ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::TYPE_INTERFACE) .concat_str(#mod_path) - .concat_str(#name); - } - - unsafe #lower_return_impl_spec { - type ReturnType = >::FfiType; - - fn lower_return(obj: Self) -> ::std::result::Result { - Ok(>::lower(::std::sync::Arc::new(obj))) - } - - const TYPE_ID_META: ::uniffi::MetadataBuffer = >::TYPE_ID_META; + .concat_str(#name) + .concat_bool(false); } unsafe #lift_ref_impl_spec { @@ -154,25 +129,18 @@ pub(crate) fn interface_impl(ident: &Ident, udl_mode: bool) -> TokenStream { pub(crate) fn interface_meta_static_var( ident: &Ident, - imp: ObjectImpl, + is_trait: bool, module_path: &str, - docstring: String, ) -> syn::Result { let name = ident_to_string(ident); - let code = match imp { - ObjectImpl::Struct => quote! { ::uniffi::metadata::codes::INTERFACE }, - ObjectImpl::Trait => quote! { ::uniffi::metadata::codes::TRAIT_INTERFACE }, - ObjectImpl::CallbackTrait => quote! { ::uniffi::metadata::codes::CALLBACK_TRAIT_INTERFACE }, - }; - Ok(create_metadata_items( "interface", &name, quote! { - ::uniffi::MetadataBuffer::from_code(#code) - .concat_str(#module_path) - .concat_str(#name) - .concat_long_str(#docstring) + ::uniffi::MetadataBuffer::from_code(::uniffi::metadata::codes::INTERFACE) + .concat_str(#module_path) + .concat_str(#name) + .concat_bool(#is_trait) }, None, )) diff --git a/third_party/rust/uniffi_macros/src/record.rs b/third_party/rust/uniffi_macros/src/record.rs index 41f5d016aceb..abf2743ec69f 100644 --- a/third_party/rust/uniffi_macros/src/record.rs +++ b/third_party/rust/uniffi_macros/src/record.rs @@ -1,20 +1,17 @@ use proc_macro2::{Ident, Span, TokenStream}; -use quote::quote; -use syn::{parse::ParseStream, Data, DataStruct, DeriveInput, Field, Token}; - -use crate::{ - default::{default_value_metadata_calls, DefaultValue}, - util::{ - create_metadata_items, derive_all_ffi_traits, either_attribute_arg, extract_docstring, - ident_to_string, kw, mod_path, tagged_impl_header, try_metadata_value_from_usize, - try_read_field, AttributeSliceExt, UniffiAttributeArgs, - }, +use quote::{quote, ToTokens}; +use syn::{ + parse::{Parse, ParseStream}, + Data, DataStruct, DeriveInput, Field, Lit, Token, +}; + +use crate::util::{ + create_metadata_items, derive_all_ffi_traits, either_attribute_arg, ident_to_string, kw, + mod_path, tagged_impl_header, try_metadata_value_from_usize, try_read_field, AttributeSliceExt, + UniffiAttributeArgs, }; pub fn expand_record(input: DeriveInput, udl_mode: bool) -> syn::Result { - if let Some(e) = input.attrs.uniffi_attr_args_not_allowed_here() { - return Err(e); - } let record = match input.data { Data::Struct(s) => s, _ => { @@ -26,12 +23,10 @@ pub fn expand_record(input: DeriveInput, udl_mode: bool) -> syn::Result TokenStream { } } +pub enum FieldDefault { + Literal(Lit), + Null(kw::None), +} + +impl ToTokens for FieldDefault { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + FieldDefault::Literal(lit) => lit.to_tokens(tokens), + FieldDefault::Null(kw) => kw.to_tokens(tokens), + } + } +} + +impl Parse for FieldDefault { + fn parse(input: ParseStream<'_>) -> syn::Result { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::None) { + let none_kw: kw::None = input.parse()?; + Ok(Self::Null(none_kw)) + } else { + Ok(Self::Literal(input.parse()?)) + } + } +} + #[derive(Default)] pub struct FieldAttributeArguments { - pub(crate) default: Option, + pub(crate) default: Option, } impl UniffiAttributeArgs for FieldAttributeArguments { @@ -107,7 +128,6 @@ impl UniffiAttributeArgs for FieldAttributeArguments { pub(crate) fn record_meta_static_var( ident: &Ident, - docstring: String, record: &DataStruct, ) -> syn::Result { let name = ident_to_string(ident); @@ -124,9 +144,17 @@ pub(crate) fn record_meta_static_var( .parse_uniffi_attr_args::()?; let name = ident_to_string(f.ident.as_ref().unwrap()); - let docstring = extract_docstring(&f.attrs)?; let ty = &f.ty; - let default = default_value_metadata_calls(&attrs.default)?; + let default = match attrs.default { + Some(default) => { + let default_value = default_value_concat_calls(default)?; + quote! { + .concat_bool(true) + #default_value + } + } + None => quote! { .concat_bool(false) }, + }; // Note: fields need to implement both `Lower` and `Lift` to be used in a record. The // TYPE_ID_META should be the same for both traits. @@ -134,7 +162,6 @@ pub(crate) fn record_meta_static_var( .concat_str(#name) .concat(<#ty as ::uniffi::Lower>::TYPE_ID_META) #default - .concat_long_str(#docstring) }) }) .collect::>()?; @@ -148,8 +175,50 @@ pub(crate) fn record_meta_static_var( .concat_str(#name) .concat_value(#fields_len) #concat_fields - .concat_long_str(#docstring) }, None, )) } + +fn default_value_concat_calls(default: FieldDefault) -> syn::Result { + match default { + FieldDefault::Literal(Lit::Int(i)) if !i.suffix().is_empty() => Err( + syn::Error::new_spanned(i, "integer literals with suffix not supported here"), + ), + FieldDefault::Literal(Lit::Float(f)) if !f.suffix().is_empty() => Err( + syn::Error::new_spanned(f, "float literals with suffix not supported here"), + ), + + FieldDefault::Literal(Lit::Str(s)) => Ok(quote! { + .concat_value(::uniffi::metadata::codes::LIT_STR) + .concat_str(#s) + }), + FieldDefault::Literal(Lit::Int(i)) => { + let digits = i.base10_digits(); + Ok(quote! { + .concat_value(::uniffi::metadata::codes::LIT_INT) + .concat_str(#digits) + }) + } + FieldDefault::Literal(Lit::Float(f)) => { + let digits = f.base10_digits(); + Ok(quote! { + .concat_value(::uniffi::metadata::codes::LIT_FLOAT) + .concat_str(#digits) + }) + } + FieldDefault::Literal(Lit::Bool(b)) => Ok(quote! { + .concat_value(::uniffi::metadata::codes::LIT_BOOL) + .concat_bool(#b) + }), + + FieldDefault::Literal(_) => Err(syn::Error::new_spanned( + default, + "this type of literal is not currently supported as a default", + )), + + FieldDefault::Null(_) => Ok(quote! { + .concat_value(::uniffi::metadata::codes::LIT_NULL) + }), + } +} diff --git a/third_party/rust/uniffi_macros/src/setup_scaffolding.rs b/third_party/rust/uniffi_macros/src/setup_scaffolding.rs index c82e9389bb61..afdb119cc41b 100644 --- a/third_party/rust/uniffi_macros/src/setup_scaffolding.rs +++ b/third_party/rust/uniffi_macros/src/setup_scaffolding.rs @@ -20,7 +20,15 @@ pub fn setup_scaffolding(namespace: String) -> Result { let ffi_rustbuffer_free_ident = format_ident!("ffi_{module_path}_rustbuffer_free"); let ffi_rustbuffer_reserve_ident = format_ident!("ffi_{module_path}_rustbuffer_reserve"); let reexport_hack_ident = format_ident!("{module_path}_uniffi_reexport_hack"); + let ffi_foreign_executor_callback_set_ident = + format_ident!("ffi_{module_path}_foreign_executor_callback_set"); + let ffi_rust_future_continuation_callback_set = + format_ident!("ffi_{module_path}_rust_future_continuation_callback_set"); let ffi_rust_future_scaffolding_fns = rust_future_scaffolding_fns(&module_path); + let continuation_cell = format_ident!( + "RUST_FUTURE_CONTINUATION_CALLBACK_CELL_{}", + module_path.to_uppercase() + ); Ok(quote! { // Unit struct to parameterize the FfiConverter trait. @@ -60,7 +68,7 @@ pub fn setup_scaffolding(namespace: String) -> Result { #[allow(clippy::missing_safety_doc, missing_docs)] #[doc(hidden)] #[no_mangle] - pub extern "C" fn #ffi_rustbuffer_alloc_ident(size: u64, call_status: &mut uniffi::RustCallStatus) -> uniffi::RustBuffer { + pub extern "C" fn #ffi_rustbuffer_alloc_ident(size: i32, call_status: &mut uniffi::RustCallStatus) -> uniffi::RustBuffer { uniffi::ffi::uniffi_rustbuffer_alloc(size, call_status) } @@ -81,10 +89,31 @@ pub fn setup_scaffolding(namespace: String) -> Result { #[allow(clippy::missing_safety_doc, missing_docs)] #[doc(hidden)] #[no_mangle] - pub unsafe extern "C" fn #ffi_rustbuffer_reserve_ident(buf: uniffi::RustBuffer, additional: u64, call_status: &mut uniffi::RustCallStatus) -> uniffi::RustBuffer { + pub unsafe extern "C" fn #ffi_rustbuffer_reserve_ident(buf: uniffi::RustBuffer, additional: i32, call_status: &mut uniffi::RustCallStatus) -> uniffi::RustBuffer { uniffi::ffi::uniffi_rustbuffer_reserve(buf, additional, call_status) } + static #continuation_cell: ::uniffi::deps::once_cell::sync::OnceCell<::uniffi::RustFutureContinuationCallback> = ::uniffi::deps::once_cell::sync::OnceCell::new(); + + #[allow(clippy::missing_safety_doc, missing_docs)] + #[doc(hidden)] + #[no_mangle] + pub extern "C" fn #ffi_foreign_executor_callback_set_ident(callback: uniffi::ffi::ForeignExecutorCallback) { + uniffi::ffi::foreign_executor_callback_set(callback) + } + + #[allow(clippy::missing_safety_doc, missing_docs)] + #[doc(hidden)] + #[no_mangle] + pub unsafe extern "C" fn #ffi_rust_future_continuation_callback_set(callback: ::uniffi::RustFutureContinuationCallback) { + if let Err(existing) = #continuation_cell.set(callback) { + // Don't panic if this to be called multiple times with the same callback. + if existing != callback { + panic!("Attempt to set the RustFuture continuation callback twice"); + } + } + } + #ffi_rust_future_scaffolding_fns // Code to re-export the UniFFI scaffolding functions. @@ -129,12 +158,12 @@ pub fn setup_scaffolding(namespace: String) -> Result { /// Generates the rust_future_* functions /// -/// The foreign side uses a type-erased `Handle` to interact with futures, which presents +/// The foreign side uses a type-erased `RustFutureHandle` to interact with futures, which presents /// a problem when creating scaffolding functions. What is the `ReturnType` parameter of `RustFutureFfi`? /// /// Handle this by using some brute-force monomorphization. For each possible ffi type, we /// generate a set of scaffolding functions. The bindings code is responsible for calling the one -/// corresponds the scaffolding function that created the `Handle`. +/// corresponds the scaffolding function that created the `RustFutureHandle`. /// /// This introduces safety issues, but we do get some type checking. If the bindings code calls /// the wrong rust_future_complete function, they should get an unexpected return type, which @@ -161,37 +190,41 @@ fn rust_future_scaffolding_fns(module_path: &str) -> TokenStream { let ffi_rust_future_cancel = format_ident!("ffi_{module_path}_rust_future_cancel_{fn_suffix}"); let ffi_rust_future_complete = format_ident!("ffi_{module_path}_rust_future_complete_{fn_suffix}"); let ffi_rust_future_free = format_ident!("ffi_{module_path}_rust_future_free_{fn_suffix}"); + let continuation_cell = format_ident!("RUST_FUTURE_CONTINUATION_CALLBACK_CELL_{}", module_path.to_uppercase()); quote! { #[allow(clippy::missing_safety_doc, missing_docs)] #[doc(hidden)] #[no_mangle] - pub unsafe extern "C" fn #ffi_rust_future_poll(handle: ::uniffi::Handle, callback: ::uniffi::RustFutureContinuationCallback, data: u64) { - ::uniffi::ffi::rust_future_poll::<#return_type, crate::UniFfiTag>(handle, callback, data); + pub unsafe extern "C" fn #ffi_rust_future_poll(handle: ::uniffi::RustFutureHandle, data: *const ()) { + let callback = #continuation_cell + .get() + .expect("RustFuture continuation callback not set. This is likely a uniffi bug."); + ::uniffi::ffi::rust_future_poll::<#return_type>(handle, *callback, data); } #[allow(clippy::missing_safety_doc, missing_docs)] #[doc(hidden)] #[no_mangle] - pub unsafe extern "C" fn #ffi_rust_future_cancel(handle: ::uniffi::Handle) { - ::uniffi::ffi::rust_future_cancel::<#return_type, crate::UniFfiTag>(handle) + pub unsafe extern "C" fn #ffi_rust_future_cancel(handle: ::uniffi::RustFutureHandle) { + ::uniffi::ffi::rust_future_cancel::<#return_type>(handle) } #[allow(clippy::missing_safety_doc, missing_docs)] #[doc(hidden)] #[no_mangle] pub unsafe extern "C" fn #ffi_rust_future_complete( - handle: ::uniffi::Handle, + handle: ::uniffi::RustFutureHandle, out_status: &mut ::uniffi::RustCallStatus ) -> #return_type { - ::uniffi::ffi::rust_future_complete::<#return_type, crate::UniFfiTag>(handle, out_status) + ::uniffi::ffi::rust_future_complete::<#return_type>(handle, out_status) } #[allow(clippy::missing_safety_doc, missing_docs)] #[doc(hidden)] #[no_mangle] - pub unsafe extern "C" fn #ffi_rust_future_free(handle: ::uniffi::Handle) { - ::uniffi::ffi::rust_future_free::<#return_type, crate::UniFfiTag>(handle) + pub unsafe extern "C" fn #ffi_rust_future_free(handle: ::uniffi::RustFutureHandle) { + ::uniffi::ffi::rust_future_free::<#return_type>(handle) } } }) diff --git a/third_party/rust/uniffi_macros/src/util.rs b/third_party/rust/uniffi_macros/src/util.rs index 97faad9c4dd2..9f213ea1d7fe 100644 --- a/third_party/rust/uniffi_macros/src/util.rs +++ b/third_party/rust/uniffi_macros/src/util.rs @@ -8,7 +8,7 @@ use std::path::{Path as StdPath, PathBuf}; use syn::{ ext::IdentExt, parse::{Parse, ParseStream}, - Attribute, Expr, Lit, Token, + Attribute, Token, }; pub fn manifest_path() -> Result { @@ -79,13 +79,8 @@ pub fn try_read_field(f: &syn::Field) -> TokenStream { let ident = &f.ident; let ty = &f.ty; - match ident { - Some(ident) => quote! { - #ident: <#ty as ::uniffi::Lift>::try_read(buf)?, - }, - None => quote! { - <#ty as ::uniffi::Lift>::try_read(buf)?, - }, + quote! { + #ident: <#ty as ::uniffi::Lift>::try_read(buf)?, } } @@ -156,7 +151,13 @@ pub fn parse_comma_separated(input: ParseStream<'_>) -> } #[derive(Default)] -struct ArgumentNotAllowedHere; +pub struct ArgumentNotAllowedHere; + +impl Parse for ArgumentNotAllowedHere { + fn parse(input: ParseStream<'_>) -> syn::Result { + parse_comma_separated(input) + } +} impl UniffiAttributeArgs for ArgumentNotAllowedHere { fn parse_one(input: ParseStream<'_>) -> syn::Result { @@ -223,11 +224,7 @@ pub(crate) fn derive_all_ffi_traits(ty: &Ident, udl_mode: bool) -> TokenStream { } } -pub(crate) fn derive_ffi_traits( - ty: impl ToTokens, - udl_mode: bool, - trait_names: &[&str], -) -> TokenStream { +pub(crate) fn derive_ffi_traits(ty: &Ident, udl_mode: bool, trait_names: &[&str]) -> TokenStream { let trait_idents = trait_names .iter() .map(|name| Ident::new(name, Span::call_site())); @@ -250,14 +247,11 @@ pub(crate) fn derive_ffi_traits( pub mod kw { syn::custom_keyword!(async_runtime); syn::custom_keyword!(callback_interface); - syn::custom_keyword!(with_foreign); + syn::custom_keyword!(constructor); syn::custom_keyword!(default); syn::custom_keyword!(flat_error); syn::custom_keyword!(None); - syn::custom_keyword!(Some); syn::custom_keyword!(with_try_read); - syn::custom_keyword!(name); - syn::custom_keyword!(non_exhaustive); syn::custom_keyword!(Debug); syn::custom_keyword!(Display); syn::custom_keyword!(Eq); @@ -282,20 +276,3 @@ impl Parse for ExternalTypeItem { }) } } - -pub(crate) fn extract_docstring(attrs: &[Attribute]) -> syn::Result { - return attrs - .iter() - .filter(|attr| attr.path().is_ident("doc")) - .map(|attr| { - let name_value = attr.meta.require_name_value()?; - if let Expr::Lit(expr) = &name_value.value { - if let Lit::Str(lit_str) = &expr.lit { - return Ok(lit_str.value().trim().to_owned()); - } - } - Err(syn::Error::new_spanned(attr, "Cannot parse doc attribute")) - }) - .collect::>>() - .map(|lines| lines.join("\n")); -} diff --git a/third_party/rust/uniffi_meta/.cargo-checksum.json b/third_party/rust/uniffi_meta/.cargo-checksum.json dissimilarity index 100% index 31b45ce80724..cb02cde83fbf 100644 --- a/third_party/rust/uniffi_meta/.cargo-checksum.json +++ b/third_party/rust/uniffi_meta/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"5620cf9840477b158641547703ba353e3ad8427ec7b20b9dd5e5f5fe4df7d6d2","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/ffi_names.rs":"ca38b700a0a103c9faaf456ed91b67adf46d4e750aee9e9cd01ad97fb1840494","src/group.rs":"d0a43f3c528aba9403649715981ad3a8849d7a370f4ef9e2d618b88f60a3102f","src/lib.rs":"3f00d5214e2785e4b3045bc48899f6f6b1dce32ab3da6be3ebce716ee9d24c5f","src/metadata.rs":"3f236b337a1fd5082ea9cc4fee6800193a903ee88b81f1c3202843402f122a14","src/reader.rs":"579e2b87d8dd9d703b8811294abfb992621c0a46765800e4db2fad2906db2208","src/types.rs":"c2c5188da8cdf5af7f8496d4660bcfaa971b81ed73b64486c05b47256048544f"},"package":"f7224422c4cfd181c7ca9fca2154abca4d21db962f926f270f996edd38b0c4b8"} \ No newline at end of file +{"files":{"Cargo.toml":"cb9f8aad563572bd4f12ee234ede6773f189a79ba5bd3bfd7622d3c0ec49d6a3","src/ffi_names.rs":"422bbe9d49d5476de752a9f9b2330f59b37a79e67f19a828caceb64d1bdabff8","src/group.rs":"ae996e6b9f83d459af04eb392e36487d0fe19c7328a395823186cce76a0955ff","src/lib.rs":"a442e2271a0eb538ec1d4fc7573a3acc7e5f366e2b2ac8d0e659fd998fd7d995","src/metadata.rs":"4ae425a8eab7b8c19a6b96c914f2c02c5bee00358888fd55b936fd1fd175a93c","src/reader.rs":"57fb771584491b8e90b01c68f9d53bac7cfa3135888e11e24e14b59312185ff9","src/types.rs":"8c155ed1301e11a365863989e29c2271149048092fb7052ec145f58c948482d5"},"package":"71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2"} \ No newline at end of file diff --git a/third_party/rust/uniffi_meta/Cargo.toml b/third_party/rust/uniffi_meta/Cargo.toml index 04d817001174..34999eee18ea 100644 --- a/third_party/rust/uniffi_meta/Cargo.toml +++ b/third_party/rust/uniffi_meta/Cargo.toml @@ -12,10 +12,9 @@ [package] edition = "2021" name = "uniffi_meta" -version = "0.27.1" +version = "0.25.3" description = "uniffi_meta" homepage = "https://mozilla.github.io/uniffi-rs" -readme = "README.md" keywords = [ "ffi", "bindgen", @@ -33,4 +32,4 @@ version = "1.3" version = "0.3" [dependencies.uniffi_checksum_derive] -version = "0.27.1" +version = "0.25.3" diff --git a/third_party/rust/uniffi_meta/README.md b/third_party/rust/uniffi_meta/README.md deleted file mode 100644 index 64ac3486a3bf..000000000000 --- a/third_party/rust/uniffi_meta/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# UniFFI - a multi-language bindings generator for Rust - -UniFFI is a toolkit for building cross-platform software components in Rust. - -For the impatient, see [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/) -or [**the UniFFI examples**](https://github.com/mozilla/uniffi-rs/tree/main/examples#example-uniffi-components). - -By writing your core business logic in Rust and describing its interface in an "object model", -you can use UniFFI to help you: - -* Compile your Rust code into a shared library for use on different target platforms. -* Generate bindings to load and use the library from different target languages. - -You can describe your object model in an [interface definition file](https://mozilla.github.io/uniffi-rs/udl_file_spec.html) -or [by using proc-macros](https://mozilla.github.io/uniffi-rs/proc_macro/index.html). - -UniFFI is currently used extensively by Mozilla in Firefox mobile and desktop browsers; -written once in Rust, auto-generated bindings allow that functionality to be called -from both Kotlin (for Android apps) and Swift (for iOS apps). -It also has a growing community of users shipping various cool things to many users. - -UniFFI comes with support for **Kotlin**, **Swift**, **Python** and **Ruby** with 3rd party bindings available for **C#** and **Golang**. -Additional foreign language bindings can be developed externally and we welcome contributions to list them here. -See [Third-party foreign language bindings](#third-party-foreign-language-bindings). - -## User Guide - -You can read more about using the tool in [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/). - -We consider it ready for production use, but UniFFI is a long way from a 1.0 release with lots of internal work still going on. -We try hard to avoid breaking simple consumers, but more advanced things might break as you upgrade over time. - -### Etymology and Pronunciation - -ˈjuːnɪfaɪ. Pronounced to rhyme with "unify". - -A portmanteau word that also puns with "unify", to signify the joining of one codebase accessed from many languages. - -uni - [Latin ūni-, from ūnus, one] -FFI - [Abbreviation, Foreign Function Interface] - -## Alternative tools - -Other tools we know of which try and solve a similarly shaped problem are: - -* [Diplomat](https://github.com/rust-diplomat/diplomat/) - see our [writeup of - the different approach taken by that tool](docs/diplomat-and-macros.md) -* [Interoptopus](https://github.com/ralfbiedert/interoptopus/) - -(Please open a PR if you think other tools should be listed!) - -## Third-party foreign language bindings - -* [Kotlin Multiplatform support](https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings). The repository contains Kotlin Multiplatform bindings generation for UniFFI, letting you target both JVM and Native. -* [Go bindings](https://github.com/NordSecurity/uniffi-bindgen-go) -* [C# bindings](https://github.com/NordSecurity/uniffi-bindgen-cs) -* [Dart bindings](https://github.com/NiallBunting/uniffi-rs-dart) - -### External resources - -There are a few third-party resources that make it easier to work with UniFFI: - -* [Plugin support for `.udl` files](https://github.com/Lonami/uniffi-dl) for the IDEA platform ([*uniffi-dl* in the JetBrains marketplace](https://plugins.jetbrains.com/plugin/20527-uniffi-dl)). It provides syntax highlighting, code folding, code completion, reference resolution and navigation (among others features) for the [UniFFI Definition Language (UDL)](https://mozilla.github.io/uniffi-rs/). -* [cargo swift](https://github.com/antoniusnaumann/cargo-swift), a cargo plugin to build a Swift Package from Rust code. It provides an init command for setting up a UniFFI crate and a package command for building a Swift package from Rust code - without the need for additional configuration or build scripts. -* [Cargo NDK Gradle Plugin](https://github.com/willir/cargo-ndk-android-gradle) allows you to build Rust code using [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk), which generally makes Android library builds less painful. -* [`uniffi-starter`](https://github.com/ianthetechie/uniffi-starter) is a minimal project demonstrates a wide range of UniFFI in a complete project in a compact manner. It includes a full Android library build process, an XCFramework generation script, and example Swift package structure. - -(Please open a PR if you think other resources should be listed!) - -## Contributing - -If this tool sounds interesting to you, please help us develop it! You can: - -* View the [contributor guidelines](./docs/contributing.md). -* File or work on [issues](https://github.com/mozilla/uniffi-rs/issues) here in GitHub. -* Join discussions in the [#uniffi:mozilla.org](https://matrix.to/#/#uniffi:mozilla.org) - room on Matrix. - -## Code of Conduct - -This project is governed by Mozilla's [Community Participation Guidelines](./CODE_OF_CONDUCT.md). diff --git a/third_party/rust/uniffi_meta/src/ffi_names.rs b/third_party/rust/uniffi_meta/src/ffi_names.rs index 5c931a09e368..44a5bc3e6377 100644 --- a/third_party/rust/uniffi_meta/src/ffi_names.rs +++ b/third_party/rust/uniffi_meta/src/ffi_names.rs @@ -33,12 +33,6 @@ pub fn method_symbol_name(namespace: &str, object_name: &str, name: &str) -> Str format!("uniffi_{namespace}_fn_method_{object_name}_{name}") } -/// FFI symbol name for the `clone` function for an object. -pub fn clone_fn_symbol_name(namespace: &str, object_name: &str) -> String { - let object_name = object_name.to_ascii_lowercase(); - format!("uniffi_{namespace}_fn_clone_{object_name}") -} - /// FFI symbol name for the `free` function for an object. pub fn free_fn_symbol_name(namespace: &str, object_name: &str) -> String { let object_name = object_name.to_ascii_lowercase(); @@ -46,12 +40,9 @@ pub fn free_fn_symbol_name(namespace: &str, object_name: &str) -> String { } /// FFI symbol name for the `init_callback` function for a callback interface -pub fn init_callback_vtable_fn_symbol_name( - namespace: &str, - callback_interface_name: &str, -) -> String { +pub fn init_callback_fn_symbol_name(namespace: &str, callback_interface_name: &str) -> String { let callback_interface_name = callback_interface_name.to_ascii_lowercase(); - format!("uniffi_{namespace}_fn_init_callback_vtable_{callback_interface_name}") + format!("uniffi_{namespace}_fn_init_callback_{callback_interface_name}") } /// FFI checksum symbol name for a top-level function diff --git a/third_party/rust/uniffi_meta/src/group.rs b/third_party/rust/uniffi_meta/src/group.rs index a41776bf8a98..f0be2e5a9871 100644 --- a/third_party/rust/uniffi_meta/src/group.rs +++ b/third_party/rust/uniffi_meta/src/group.rs @@ -18,7 +18,6 @@ pub fn create_metadata_groups(items: &[Metadata]) -> MetadataGroupMap { Metadata::Namespace(namespace) => { let group = MetadataGroup { namespace: namespace.clone(), - namespace_docstring: None, items: BTreeSet::new(), }; Some((namespace.crate_name.clone(), group)) @@ -30,7 +29,6 @@ pub fn create_metadata_groups(items: &[Metadata]) -> MetadataGroupMap { }; let group = MetadataGroup { namespace, - namespace_docstring: None, items: BTreeSet::new(), }; Some((udl.module_path.clone(), group)) @@ -65,7 +63,6 @@ pub fn group_metadata(group_map: &mut MetadataGroupMap, items: Vec) -> #[derive(Debug)] pub struct MetadataGroup { pub namespace: NamespaceMetadata, - pub namespace_docstring: Option, pub items: BTreeSet, } @@ -130,6 +127,12 @@ impl<'a> ExternalTypeConverter<'a> { ..meta }), Metadata::Enum(meta) => Metadata::Enum(self.convert_enum(meta)), + Metadata::Error(meta) => Metadata::Error(match meta { + ErrorMetadata::Enum { enum_, is_flat } => ErrorMetadata::Enum { + enum_: self.convert_enum(enum_), + is_flat, + }, + }), _ => item, } } diff --git a/third_party/rust/uniffi_meta/src/lib.rs b/third_party/rust/uniffi_meta/src/lib.rs index 90f7b2d3cdcf..e486d84d8963 100644 --- a/third_party/rust/uniffi_meta/src/lib.rs +++ b/third_party/rust/uniffi_meta/src/lib.rs @@ -23,7 +23,7 @@ mod metadata; // `docs/uniffi-versioning.md` for details. // // Once we get to 1.0, then we'll need to update the scheme to something like 100 + major_version -pub const UNIFFI_CONTRACT_VERSION: u32 = 26; +pub const UNIFFI_CONTRACT_VERSION: u32 = 24; /// Similar to std::hash::Hash. /// @@ -143,7 +143,6 @@ pub struct FnMetadata { pub return_type: Option, pub throws: Option, pub checksum: Option, - pub docstring: Option, } impl FnMetadata { @@ -161,11 +160,9 @@ pub struct ConstructorMetadata { pub module_path: String, pub self_name: String, pub name: String, - pub is_async: bool, pub inputs: Vec, pub throws: Option, pub checksum: Option, - pub docstring: Option, } impl ConstructorMetadata { @@ -193,7 +190,6 @@ pub struct MethodMetadata { pub throws: Option, pub takes_self_by_arc: bool, // unused except by rust udl bindgen. pub checksum: Option, - pub docstring: Option, } impl MethodMetadata { @@ -220,7 +216,6 @@ pub struct TraitMethodMetadata { pub throws: Option, pub takes_self_by_arc: bool, // unused except by rust udl bindgen. pub checksum: Option, - pub docstring: Option, } impl TraitMethodMetadata { @@ -271,17 +266,7 @@ pub enum LiteralMetadata { Enum(String, Type), EmptySequence, EmptyMap, - None, - Some { inner: Box }, -} - -impl LiteralMetadata { - pub fn new_uint(v: u64) -> Self { - LiteralMetadata::UInt(v, Radix::Decimal, Type::UInt64) - } - pub fn new_int(v: i64) -> Self { - LiteralMetadata::Int(v, Radix::Decimal, Type::Int64) - } + Null, } // Represent the radix of integer literal values. @@ -298,7 +283,6 @@ pub struct RecordMetadata { pub module_path: String, pub name: String, pub fields: Vec, - pub docstring: Option, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] @@ -306,26 +290,19 @@ pub struct FieldMetadata { pub name: String, pub ty: Type, pub default: Option, - pub docstring: Option, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct EnumMetadata { pub module_path: String, pub name: String, - pub forced_flatness: Option, pub variants: Vec, - pub discr_type: Option, - pub non_exhaustive: bool, - pub docstring: Option, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct VariantMetadata { pub name: String, - pub discr: Option, pub fields: Vec, - pub docstring: Option, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] @@ -333,25 +310,15 @@ pub struct ObjectMetadata { pub module_path: String, pub name: String, pub imp: types::ObjectImpl, - pub docstring: Option, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct CallbackInterfaceMetadata { pub module_path: String, pub name: String, - pub docstring: Option, } impl ObjectMetadata { - /// FFI symbol name for the `clone` function for this object. - /// - /// This function is used to increment the reference count before lowering an object to pass - /// back to Rust. - pub fn clone_ffi_symbol_name(&self) -> String { - clone_fn_symbol_name(&self.module_path, &self.name) - } - /// FFI symbol name for the `free` function for this object. /// /// This function is used to free the memory used by this object. @@ -401,7 +368,6 @@ impl UniffiTraitMetadata { } #[repr(u8)] -#[derive(Eq, PartialEq, Hash)] pub enum UniffiTraitDiscriminants { Debug, Display, @@ -422,6 +388,25 @@ impl UniffiTraitDiscriminants { } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ErrorMetadata { + Enum { enum_: EnumMetadata, is_flat: bool }, +} + +impl ErrorMetadata { + pub fn name(&self) -> &String { + match self { + Self::Enum { enum_, .. } => &enum_.name, + } + } + + pub fn module_path(&self) -> &String { + match self { + Self::Enum { enum_, .. } => &enum_.module_path, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct CustomTypeMetadata { pub module_path: String, pub name: String, @@ -448,6 +433,7 @@ pub enum Metadata { CallbackInterface(CallbackInterfaceMetadata), Record(RecordMetadata), Enum(EnumMetadata), + Error(ErrorMetadata), Constructor(ConstructorMetadata), Method(MethodMetadata), TraitMethod(TraitMethodMetadata), @@ -472,6 +458,7 @@ impl Metadata { Metadata::Object(meta) => &meta.module_path, Metadata::CallbackInterface(meta) => &meta.module_path, Metadata::TraitMethod(meta) => &meta.module_path, + Metadata::Error(meta) => meta.module_path(), Metadata::CustomType(meta) => &meta.module_path, Metadata::UniffiTrait(meta) => meta.module_path(), } @@ -520,6 +507,12 @@ impl From for Metadata { } } +impl From for Metadata { + fn from(e: ErrorMetadata) -> Self { + Self::Error(e) + } +} + impl From for Metadata { fn from(v: ObjectMetadata) -> Self { Self::Object(v) diff --git a/third_party/rust/uniffi_meta/src/metadata.rs b/third_party/rust/uniffi_meta/src/metadata.rs index 9cfb77a244a4..6e490a48663c 100644 --- a/third_party/rust/uniffi_meta/src/metadata.rs +++ b/third_party/rust/uniffi_meta/src/metadata.rs @@ -7,7 +7,7 @@ // `uniffi_core`. // This is the easy way out of that issue and is a temporary hacky solution. -/// Metadata constants, make sure to keep this in sync with copy in `uniffi_core::metadata` +/// Metadata constants, make sure to keep this in sync with copy in `uniffi_meta::reader` pub mod codes { // Top-level metadata item codes pub const FUNC: u8 = 0; @@ -15,14 +15,13 @@ pub mod codes { pub const RECORD: u8 = 2; pub const ENUM: u8 = 3; pub const INTERFACE: u8 = 4; + pub const ERROR: u8 = 5; pub const NAMESPACE: u8 = 6; pub const CONSTRUCTOR: u8 = 7; pub const UDL_FILE: u8 = 8; pub const CALLBACK_INTERFACE: u8 = 9; pub const TRAIT_METHOD: u8 = 10; pub const UNIFFI_TRAIT: u8 = 11; - pub const TRAIT_INTERFACE: u8 = 12; - pub const CALLBACK_TRAIT_INTERFACE: u8 = 13; //pub const UNKNOWN: u8 = 255; // Type codes @@ -50,8 +49,8 @@ pub mod codes { pub const TYPE_CALLBACK_INTERFACE: u8 = 21; pub const TYPE_CUSTOM: u8 = 22; pub const TYPE_RESULT: u8 = 23; - pub const TYPE_TRAIT_INTERFACE: u8 = 24; - pub const TYPE_CALLBACK_TRAIT_INTERFACE: u8 = 25; + //pub const TYPE_FUTURE: u8 = 24; + pub const TYPE_FOREIGN_EXECUTOR: u8 = 25; pub const TYPE_UNIT: u8 = 255; // Literal codes @@ -59,9 +58,7 @@ pub mod codes { pub const LIT_INT: u8 = 1; pub const LIT_FLOAT: u8 = 2; pub const LIT_BOOL: u8 = 3; - pub const LIT_NONE: u8 = 4; - pub const LIT_SOME: u8 = 5; - pub const LIT_EMPTY_SEQ: u8 = 6; + pub const LIT_NULL: u8 = 4; } // Create a checksum for a MetadataBuffer diff --git a/third_party/rust/uniffi_meta/src/reader.rs b/third_party/rust/uniffi_meta/src/reader.rs index 6fec6cb3a359..bf6525f2b508 100644 --- a/third_party/rust/uniffi_meta/src/reader.rs +++ b/third_party/rust/uniffi_meta/src/reader.rs @@ -52,10 +52,9 @@ impl<'a> MetadataReader<'a> { codes::CONSTRUCTOR => self.read_constructor()?.into(), codes::METHOD => self.read_method()?.into(), codes::RECORD => self.read_record()?.into(), - codes::ENUM => self.read_enum()?.into(), - codes::INTERFACE => self.read_object(ObjectImpl::Struct)?.into(), - codes::TRAIT_INTERFACE => self.read_object(ObjectImpl::Trait)?.into(), - codes::CALLBACK_TRAIT_INTERFACE => self.read_object(ObjectImpl::CallbackTrait)?.into(), + codes::ENUM => self.read_enum(false)?.into(), + codes::ERROR => self.read_error()?.into(), + codes::INTERFACE => self.read_object()?.into(), codes::CALLBACK_INTERFACE => self.read_callback_interface()?.into(), codes::TRAIT_METHOD => self.read_trait_method()?.into(), codes::UNIFFI_TRAIT => self.read_uniffi_trait()?.into(), @@ -81,17 +80,6 @@ impl<'a> MetadataReader<'a> { } } - fn read_u16(&mut self) -> Result { - if self.buf.len() >= 2 { - // read the value as little-endian - let value = u16::from_le_bytes([self.buf[0], self.buf[1]]); - self.buf = &self.buf[2..]; - Ok(value) - } else { - bail!("Not enough data left in buffer to read a u16 value"); - } - } - fn read_u32(&mut self) -> Result { if self.buf.len() >= 4 { // read the value as little-endian @@ -117,17 +105,6 @@ impl<'a> MetadataReader<'a> { String::from_utf8(slice.into()).context("Invalid string data") } - fn read_long_string(&mut self) -> Result { - let size = self.read_u16()? as usize; - let slice; - (slice, self.buf) = self.buf.split_at(size); - String::from_utf8(slice.into()).context("Invalid string data") - } - - fn read_optional_long_string(&mut self) -> Result> { - Ok(Some(self.read_long_string()?).filter(|str| !str.is_empty())) - } - fn read_type(&mut self) -> Result { let value = self.read_u8()?; Ok(match value { @@ -145,6 +122,7 @@ impl<'a> MetadataReader<'a> { codes::TYPE_STRING => Type::String, codes::TYPE_DURATION => Type::Duration, codes::TYPE_SYSTEM_TIME => Type::Timestamp, + codes::TYPE_FOREIGN_EXECUTOR => Type::ForeignExecutor, codes::TYPE_RECORD => Type::Record { module_path: self.read_string()?, name: self.read_string()?, @@ -156,17 +134,7 @@ impl<'a> MetadataReader<'a> { codes::TYPE_INTERFACE => Type::Object { module_path: self.read_string()?, name: self.read_string()?, - imp: ObjectImpl::Struct, - }, - codes::TYPE_TRAIT_INTERFACE => Type::Object { - module_path: self.read_string()?, - name: self.read_string()?, - imp: ObjectImpl::Trait, - }, - codes::TYPE_CALLBACK_TRAIT_INTERFACE => Type::Object { - module_path: self.read_string()?, - name: self.read_string()?, - imp: ObjectImpl::CallbackTrait, + imp: ObjectImpl::from_is_trait(self.read_bool()?), }, codes::TYPE_CALLBACK_INTERFACE => Type::CallbackInterface { module_path: self.read_string()?, @@ -230,7 +198,6 @@ impl<'a> MetadataReader<'a> { let is_async = self.read_bool()?; let inputs = self.read_inputs()?; let (return_type, throws) = self.read_return_type()?; - let docstring = self.read_optional_long_string()?; Ok(FnMetadata { module_path, name, @@ -238,7 +205,6 @@ impl<'a> MetadataReader<'a> { inputs, return_type, throws, - docstring, checksum: self.calc_checksum(), }) } @@ -247,10 +213,8 @@ impl<'a> MetadataReader<'a> { let module_path = self.read_string()?; let self_name = self.read_string()?; let name = self.read_string()?; - let is_async = self.read_bool()?; let inputs = self.read_inputs()?; let (return_type, throws) = self.read_return_type()?; - let docstring = self.read_optional_long_string()?; return_type .filter(|t| { @@ -264,12 +228,10 @@ impl<'a> MetadataReader<'a> { Ok(ConstructorMetadata { module_path, self_name, - is_async, name, inputs, throws, checksum: self.calc_checksum(), - docstring, }) } @@ -280,7 +242,6 @@ impl<'a> MetadataReader<'a> { let is_async = self.read_bool()?; let inputs = self.read_inputs()?; let (return_type, throws) = self.read_return_type()?; - let docstring = self.read_optional_long_string()?; Ok(MethodMetadata { module_path, self_name, @@ -291,7 +252,6 @@ impl<'a> MetadataReader<'a> { throws, takes_self_by_arc: false, // not emitted by macros checksum: self.calc_checksum(), - docstring, }) } @@ -300,25 +260,13 @@ impl<'a> MetadataReader<'a> { module_path: self.read_string()?, name: self.read_string()?, fields: self.read_fields()?, - docstring: self.read_optional_long_string()?, }) } - fn read_enum(&mut self) -> Result { + fn read_enum(&mut self, is_flat_error: bool) -> Result { let module_path = self.read_string()?; let name = self.read_string()?; - let forced_flatness = match self.read_u8()? { - 0 => None, - 1 => Some(false), - 2 => Some(true), - _ => unreachable!("invalid flatness"), - }; - let discr_type = if self.read_bool()? { - Some(self.read_type()?) - } else { - None - }; - let variants = if forced_flatness == Some(true) { + let variants = if is_flat_error { self.read_flat_variants()? } else { self.read_variants()? @@ -327,20 +275,21 @@ impl<'a> MetadataReader<'a> { Ok(EnumMetadata { module_path, name, - forced_flatness, - discr_type, variants, - non_exhaustive: self.read_bool()?, - docstring: self.read_optional_long_string()?, }) } - fn read_object(&mut self, imp: ObjectImpl) -> Result { + fn read_error(&mut self) -> Result { + let is_flat = self.read_bool()?; + let enum_ = self.read_enum(is_flat)?; + Ok(ErrorMetadata::Enum { enum_, is_flat }) + } + + fn read_object(&mut self) -> Result { Ok(ObjectMetadata { module_path: self.read_string()?, name: self.read_string()?, - imp, - docstring: self.read_optional_long_string()?, + imp: ObjectImpl::from_is_trait(self.read_bool()?), }) } @@ -373,7 +322,6 @@ impl<'a> MetadataReader<'a> { Ok(CallbackInterfaceMetadata { module_path: self.read_string()?, name: self.read_string()?, - docstring: self.read_optional_long_string()?, }) } @@ -385,7 +333,6 @@ impl<'a> MetadataReader<'a> { let is_async = self.read_bool()?; let inputs = self.read_inputs()?; let (return_type, throws) = self.read_return_type()?; - let docstring = self.read_optional_long_string()?; Ok(TraitMethodMetadata { module_path, trait_name, @@ -397,7 +344,6 @@ impl<'a> MetadataReader<'a> { throws, takes_self_by_arc: false, // not emitted by macros checksum: self.calc_checksum(), - docstring, }) } @@ -407,13 +353,8 @@ impl<'a> MetadataReader<'a> { .map(|_| { let name = self.read_string()?; let ty = self.read_type()?; - let default = self.read_optional_default(&name, &ty)?; - Ok(FieldMetadata { - name, - ty, - default, - docstring: self.read_optional_long_string()?, - }) + let default = self.read_default(&name, &ty)?; + Ok(FieldMetadata { name, ty, default }) }) .collect() } @@ -424,9 +365,7 @@ impl<'a> MetadataReader<'a> { .map(|_| { Ok(VariantMetadata { name: self.read_string()?, - discr: self.read_optional_default("", &Type::UInt64)?, fields: self.read_fields()?, - docstring: self.read_optional_long_string()?, }) }) .collect() @@ -438,9 +377,7 @@ impl<'a> MetadataReader<'a> { .map(|_| { Ok(VariantMetadata { name: self.read_string()?, - discr: None, fields: vec![], - docstring: self.read_optional_long_string()?, }) }) .collect() @@ -450,16 +387,13 @@ impl<'a> MetadataReader<'a> { let len = self.read_u8()?; (0..len) .map(|_| { - let name = self.read_string()?; - let ty = self.read_type()?; - let default = self.read_optional_default(&name, &ty)?; Ok(FnParamMetadata { - name, - ty, - default, + name: self.read_string()?, + ty: self.read_type()?, // not emitted by macros by_ref: false, optional: false, + default: None, }) }) .collect() @@ -471,18 +405,14 @@ impl<'a> MetadataReader<'a> { Some(checksum_metadata(metadata_buf)) } - fn read_optional_default(&mut self, name: &str, ty: &Type) -> Result> { - if self.read_bool()? { - Ok(Some(self.read_default(name, ty)?)) - } else { - Ok(None) + fn read_default(&mut self, name: &str, ty: &Type) -> Result> { + let has_default = self.read_bool()?; + if !has_default { + return Ok(None); } - } - fn read_default(&mut self, name: &str, ty: &Type) -> Result { let literal_kind = self.read_u8()?; - - Ok(match literal_kind { + Ok(Some(match literal_kind { codes::LIT_STR => { ensure!( matches!(ty, Type::String), @@ -492,24 +422,12 @@ impl<'a> MetadataReader<'a> { } codes::LIT_INT => { let base10_digits = self.read_string()?; - // procmacros emit the type for discriminant values based purely on whether the constant - // is positive or negative. - let ty = if !base10_digits.is_empty() - && base10_digits.as_bytes()[0] == b'-' - && ty == &Type::UInt64 - { - &Type::Int64 - } else { - ty - }; macro_rules! parse_int { ($ty:ident, $variant:ident) => { LiteralMetadata::$variant( base10_digits .parse::<$ty>() - .with_context(|| { - format!("parsing default for field {name}: {base10_digits}") - })? + .with_context(|| format!("parsing default for field {name}"))? .into(), Radix::Decimal, ty.to_owned(), @@ -540,18 +458,8 @@ impl<'a> MetadataReader<'a> { } }, codes::LIT_BOOL => LiteralMetadata::Boolean(self.read_bool()?), - codes::LIT_NONE => match ty { - Type::Optional { .. } => LiteralMetadata::None, - _ => bail!("field {name} of type {ty:?} can't have a default value of None"), - }, - codes::LIT_SOME => match ty { - Type::Optional { inner_type, .. } => LiteralMetadata::Some { - inner: Box::new(self.read_default(name, inner_type)?), - }, - _ => bail!("field {name} of type {ty:?} can't have a default value of None"), - }, - codes::LIT_EMPTY_SEQ => LiteralMetadata::EmptySequence, + codes::LIT_NULL => LiteralMetadata::Null, _ => bail!("Unexpected literal kind code: {literal_kind:?}"), - }) + })) } } diff --git a/third_party/rust/uniffi_meta/src/types.rs b/third_party/rust/uniffi_meta/src/types.rs index 51bf156b50b1..24f8a6f2a872 100644 --- a/third_party/rust/uniffi_meta/src/types.rs +++ b/third_party/rust/uniffi_meta/src/types.rs @@ -21,12 +21,8 @@ use crate::Checksum; #[derive(Debug, Copy, Clone, Eq, PartialEq, Checksum, Ord, PartialOrd)] pub enum ObjectImpl { - // A single Rust type Struct, - // A trait that's can be implemented by Rust types Trait, - // A trait + a callback interface -- can be implemented by both Rust and foreign types. - CallbackTrait, } impl ObjectImpl { @@ -35,26 +31,27 @@ impl ObjectImpl { /// Includes `r#`, traits get a leading `dyn`. If we ever supported associated types, then /// this would also include them. pub fn rust_name_for(&self, name: &str) -> String { - if self.is_trait_interface() { + if self == &ObjectImpl::Trait { format!("dyn r#{name}") } else { format!("r#{name}") } } - pub fn is_trait_interface(&self) -> bool { - matches!(self, Self::Trait | Self::CallbackTrait) - } - - pub fn has_callback_interface(&self) -> bool { - matches!(self, Self::CallbackTrait) + // uniffi_meta and procmacro support tend to carry around `is_trait` bools. This makes that + // mildly less painful + pub fn from_is_trait(is_trait: bool) -> Self { + if is_trait { + ObjectImpl::Trait + } else { + ObjectImpl::Struct + } } } #[derive(Debug, Clone, Copy, Eq, PartialEq, Checksum, Ord, PartialOrd)] pub enum ExternalKind { Interface, - Trait, // Either a record or enum DataClass, } @@ -88,6 +85,7 @@ pub enum Type { // How the object is implemented. imp: ObjectImpl, }, + ForeignExecutor, // Types defined in the component API, each of which has a string name. Record { module_path: String, diff --git a/third_party/rust/uniffi_testing/.cargo-checksum.json b/third_party/rust/uniffi_testing/.cargo-checksum.json index 47b58d8bcfac..0af9b557d8d3 100644 --- a/third_party/rust/uniffi_testing/.cargo-checksum.json +++ b/third_party/rust/uniffi_testing/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f29ebbc363e01ee31c5a351aa6c19bc99343b4d293d5ea7954bca3f49e77ad54","README.md":"ec6aba24af9a011ef6647422aa22efabdee519cdee3da1a9f9033b07b7cbdb0d","src/lib.rs":"e19f60aed5a137401203b9054ead27894b98490bab3e2f680a23549c8ee8a13a"},"package":"f8ce878d0bdfc288b58797044eaaedf748526c56eef3575380bb4d4b19d69eee"} \ No newline at end of file +{"files":{"Cargo.toml":"300889e9b31b2f73133d69a8c5f8854c72cefd398b4f656c7fc06f4c46475dcc","README.md":"ec6aba24af9a011ef6647422aa22efabdee519cdee3da1a9f9033b07b7cbdb0d","src/lib.rs":"e19f60aed5a137401203b9054ead27894b98490bab3e2f680a23549c8ee8a13a"},"package":"118448debffcb676ddbe8c5305fb933ab7e0123753e659a71dc4a693f8d9f23c"} \ No newline at end of file diff --git a/third_party/rust/uniffi_testing/Cargo.toml b/third_party/rust/uniffi_testing/Cargo.toml index 5dacf0cf3172..a4f6f0bf5452 100644 --- a/third_party/rust/uniffi_testing/Cargo.toml +++ b/third_party/rust/uniffi_testing/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2021" name = "uniffi_testing" -version = "0.27.1" +version = "0.25.3" authors = ["Firefox Sync Team "] description = "a multi-language bindings generator for rust (testing helpers)" homepage = "https://mozilla.github.io/uniffi-rs" diff --git a/third_party/rust/uniffi_udl/.cargo-checksum.json b/third_party/rust/uniffi_udl/.cargo-checksum.json dissimilarity index 100% index 88ed1cb4b78e..233a1e7795d2 100644 --- a/third_party/rust/uniffi_udl/.cargo-checksum.json +++ b/third_party/rust/uniffi_udl/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"e4553df91528daadbc52244f436c3ae17d9c6a4629d232643a20ed63c1311625","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/attributes.rs":"f1cdee01db837920dbd109d60b39dd4b0ece56f83797fe4ace1e0caf97c02483","src/collectors.rs":"00c9cd8e8f7be6949996f069b449f120f0b0694ff2f1ca92b79201721c18c594","src/converters/callables.rs":"1ad26c2782629e98272edc75c38343f58194ebf9626ae451ba84546a60d45a48","src/converters/enum_.rs":"aa0ca7a7a50521a45e296c6f53be5f1981a41872443946f72c2ca8baebe4d69b","src/converters/interface.rs":"6042d4abd5e236ed6158c5f6d4d9b81bb01fbbcb8b42bf8a5b385b978c68f6f8","src/converters/mod.rs":"c34a30e3b7a2e3c092a7074f4bab6f6c34364177c096af59a7dda13e44ffdc3c","src/finder.rs":"3586ffd3772151eabbc3d6062725933c88978e1b5feb64312bbf42cd43af30fa","src/lib.rs":"56c50ce61ba5e7266fe7fc9fa9d0022cdbfbe9801730753bd4ee66fed040221c","src/literal.rs":"4f28ad49a17246b4dc30a677cfff65b345bfac0924856e19f58e7574a74c2c40","src/resolver.rs":"c4ff362055dc4ed489e94a063ec0fd3becb8787ad35ce65cdec437a1aae518a0"},"package":"8c43c9ed40a8d20a5c3eae2d23031092db6b96dc8e571beb449ba9757484cea0"} \ No newline at end of file +{"files":{"Cargo.toml":"8bb1bcb6089114c92a0d06f884e64769edc493bd26d271eb659d6592d8d2f5fa","src/attributes.rs":"faf1c53c17ff511f587113afdb37de4890087150f32e19c9af4d878daebe7c89","src/collectors.rs":"3d80f169ccb7a64c434a6890948e49a64947062c29487b5bea58721189cb2786","src/converters/callables.rs":"c41d15cf816f5838e74f0c1d7a5806c4f1c1b2d925ca11b2b6658a978b2373fb","src/converters/enum_.rs":"1742441b812949b83ec28c2c2c4684c34fd618195cff47af2934c7ee9c895c59","src/converters/interface.rs":"a3deb1915eb4be80d21116f24bec7163736bdffbad4eb2236fb531386a97c4f8","src/converters/mod.rs":"4035ec70c56917fa7c61cced5f8a8398c99028e13959662acc1f7a48aa71ae3b","src/finder.rs":"c496aca0ac640d4ca5fd57b32131297544e5468c9e792f8b5da1644df6d22d2e","src/lib.rs":"11a5d3c288f5786164471b0870b5ca9190305757461c6a6d20777a96622457f1","src/literal.rs":"30e50d7c1d3f061bb6aaa7ad3a6eb31d75a6ea21159dfe454f7ab9ae4bdb580e","src/resolver.rs":"96212b52c4f4f7637713d0a39f5c4972e6480e4ce98070dcb8647d67c9b8d5e2"},"package":"889edb7109c6078abe0e53e9b4070cf74a6b3468d141bdf5ef1bd4d1dc24a1c3"} \ No newline at end of file diff --git a/third_party/rust/uniffi_udl/Cargo.toml b/third_party/rust/uniffi_udl/Cargo.toml index fd03f3434af8..346cd71c2791 100644 --- a/third_party/rust/uniffi_udl/Cargo.toml +++ b/third_party/rust/uniffi_udl/Cargo.toml @@ -12,11 +12,10 @@ [package] edition = "2021" name = "uniffi_udl" -version = "0.27.1" +version = "0.25.3" description = "udl parsing for the uniffi project" homepage = "https://mozilla.github.io/uniffi-rs" documentation = "https://mozilla.github.io/uniffi-rs" -readme = "README.md" keywords = [ "ffi", "bindgen", @@ -27,14 +26,11 @@ repository = "https://github.com/mozilla/uniffi-rs" [dependencies.anyhow] version = "1" -[dependencies.textwrap] -version = "0.16" - [dependencies.uniffi_meta] -version = "=0.27.1" +version = "=0.25.3" [dependencies.uniffi_testing] -version = "=0.27.1" +version = "=0.25.3" [dependencies.weedle2] -version = "5.0.0" +version = "4.0.0" diff --git a/third_party/rust/uniffi_udl/README.md b/third_party/rust/uniffi_udl/README.md deleted file mode 100644 index 64ac3486a3bf..000000000000 --- a/third_party/rust/uniffi_udl/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# UniFFI - a multi-language bindings generator for Rust - -UniFFI is a toolkit for building cross-platform software components in Rust. - -For the impatient, see [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/) -or [**the UniFFI examples**](https://github.com/mozilla/uniffi-rs/tree/main/examples#example-uniffi-components). - -By writing your core business logic in Rust and describing its interface in an "object model", -you can use UniFFI to help you: - -* Compile your Rust code into a shared library for use on different target platforms. -* Generate bindings to load and use the library from different target languages. - -You can describe your object model in an [interface definition file](https://mozilla.github.io/uniffi-rs/udl_file_spec.html) -or [by using proc-macros](https://mozilla.github.io/uniffi-rs/proc_macro/index.html). - -UniFFI is currently used extensively by Mozilla in Firefox mobile and desktop browsers; -written once in Rust, auto-generated bindings allow that functionality to be called -from both Kotlin (for Android apps) and Swift (for iOS apps). -It also has a growing community of users shipping various cool things to many users. - -UniFFI comes with support for **Kotlin**, **Swift**, **Python** and **Ruby** with 3rd party bindings available for **C#** and **Golang**. -Additional foreign language bindings can be developed externally and we welcome contributions to list them here. -See [Third-party foreign language bindings](#third-party-foreign-language-bindings). - -## User Guide - -You can read more about using the tool in [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/). - -We consider it ready for production use, but UniFFI is a long way from a 1.0 release with lots of internal work still going on. -We try hard to avoid breaking simple consumers, but more advanced things might break as you upgrade over time. - -### Etymology and Pronunciation - -ˈjuːnɪfaɪ. Pronounced to rhyme with "unify". - -A portmanteau word that also puns with "unify", to signify the joining of one codebase accessed from many languages. - -uni - [Latin ūni-, from ūnus, one] -FFI - [Abbreviation, Foreign Function Interface] - -## Alternative tools - -Other tools we know of which try and solve a similarly shaped problem are: - -* [Diplomat](https://github.com/rust-diplomat/diplomat/) - see our [writeup of - the different approach taken by that tool](docs/diplomat-and-macros.md) -* [Interoptopus](https://github.com/ralfbiedert/interoptopus/) - -(Please open a PR if you think other tools should be listed!) - -## Third-party foreign language bindings - -* [Kotlin Multiplatform support](https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings). The repository contains Kotlin Multiplatform bindings generation for UniFFI, letting you target both JVM and Native. -* [Go bindings](https://github.com/NordSecurity/uniffi-bindgen-go) -* [C# bindings](https://github.com/NordSecurity/uniffi-bindgen-cs) -* [Dart bindings](https://github.com/NiallBunting/uniffi-rs-dart) - -### External resources - -There are a few third-party resources that make it easier to work with UniFFI: - -* [Plugin support for `.udl` files](https://github.com/Lonami/uniffi-dl) for the IDEA platform ([*uniffi-dl* in the JetBrains marketplace](https://plugins.jetbrains.com/plugin/20527-uniffi-dl)). It provides syntax highlighting, code folding, code completion, reference resolution and navigation (among others features) for the [UniFFI Definition Language (UDL)](https://mozilla.github.io/uniffi-rs/). -* [cargo swift](https://github.com/antoniusnaumann/cargo-swift), a cargo plugin to build a Swift Package from Rust code. It provides an init command for setting up a UniFFI crate and a package command for building a Swift package from Rust code - without the need for additional configuration or build scripts. -* [Cargo NDK Gradle Plugin](https://github.com/willir/cargo-ndk-android-gradle) allows you to build Rust code using [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk), which generally makes Android library builds less painful. -* [`uniffi-starter`](https://github.com/ianthetechie/uniffi-starter) is a minimal project demonstrates a wide range of UniFFI in a complete project in a compact manner. It includes a full Android library build process, an XCFramework generation script, and example Swift package structure. - -(Please open a PR if you think other resources should be listed!) - -## Contributing - -If this tool sounds interesting to you, please help us develop it! You can: - -* View the [contributor guidelines](./docs/contributing.md). -* File or work on [issues](https://github.com/mozilla/uniffi-rs/issues) here in GitHub. -* Join discussions in the [#uniffi:mozilla.org](https://matrix.to/#/#uniffi:mozilla.org) - room on Matrix. - -## Code of Conduct - -This project is governed by Mozilla's [Community Participation Guidelines](./CODE_OF_CONDUCT.md). diff --git a/third_party/rust/uniffi_udl/src/attributes.rs b/third_party/rust/uniffi_udl/src/attributes.rs index 7bb05808c484..f06b4f29c192 100644 --- a/third_party/rust/uniffi_udl/src/attributes.rs +++ b/third_party/rust/uniffi_udl/src/attributes.rs @@ -37,29 +37,10 @@ pub(super) enum Attribute { kind: ExternalKind, export: bool, }, - Rust { - kind: RustKind, - }, // Custom type on the scaffolding side Custom, // The interface described is implemented as a trait. Trait, - // Modifies `Trait` to enable foreign implementations (callback interfaces) - WithForeign, - Async, - NonExhaustive, -} - -// A type defined in Rust via procmacros but which should be available -// in UDL. -#[derive(Debug, Copy, Clone, Checksum)] -pub(super) enum RustKind { - Object, - CallbackTrait, - Trait, - Record, - Enum, - CallbackInterface, } impl Attribute { @@ -86,9 +67,6 @@ impl TryFrom<&weedle::attribute::ExtendedAttribute<'_>> for Attribute { "Error" => Ok(Attribute::Error), "Custom" => Ok(Attribute::Custom), "Trait" => Ok(Attribute::Trait), - "WithForeign" => Ok(Attribute::WithForeign), - "Async" => Ok(Attribute::Async), - "NonExhaustive" => Ok(Attribute::NonExhaustive), _ => anyhow::bail!("ExtendedAttributeNoArgs not supported: {:?}", (attr.0).0), }, // Matches assignment-style attributes like ["Throws=Error"] @@ -117,19 +95,6 @@ impl TryFrom<&weedle::attribute::ExtendedAttribute<'_>> for Attribute { kind: ExternalKind::Interface, export: true, }), - "ExternalTrait" => Ok(Attribute::External { - crate_name: name_from_id_or_string(&identity.rhs), - kind: ExternalKind::Trait, - export: false, - }), - "ExternalTraitExport" => Ok(Attribute::External { - crate_name: name_from_id_or_string(&identity.rhs), - kind: ExternalKind::Trait, - export: true, - }), - "Rust" => Ok(Attribute::Rust { - kind: rust_kind_from_id_or_string(&identity.rhs)?, - }), _ => anyhow::bail!( "Attribute identity Identifier not supported: {:?}", identity.lhs_identifier.0 @@ -165,26 +130,6 @@ fn name_from_id_or_string(nm: &weedle::attribute::IdentifierOrString<'_>) -> Str } } -fn rust_kind_from_id_or_string(nm: &weedle::attribute::IdentifierOrString<'_>) -> Result { - Ok(match nm { - weedle::attribute::IdentifierOrString::String(str_lit) => match str_lit.0 { - // support names which match either procmacro or udl - "interface" => RustKind::Object, - "object" => RustKind::Object, - "record" => RustKind::Record, - "dictionary" => RustKind::Record, - "enum" => RustKind::Enum, - "trait" => RustKind::Trait, - "callback" => RustKind::CallbackInterface, - "trait_with_foreign" => RustKind::CallbackTrait, - _ => anyhow::bail!("Unknown `[Rust=]` kind {:?}", str_lit.0), - }, - weedle::attribute::IdentifierOrString::Identifier(_) => { - anyhow::bail!("Expected string attribute value, got identifier") - } - }) -} - /// Parse a weedle `ExtendedAttributeList` into a list of `Attribute`s, /// erroring out on duplicates. fn parse_attributes( @@ -216,6 +161,7 @@ where } /// Attributes that can be attached to an `enum` definition in the UDL. +/// There's only one case here: using `[Error]` to mark an enum as an error class. #[derive(Debug, Clone, Checksum, Default)] pub(super) struct EnumAttributes(Vec); @@ -223,12 +169,6 @@ impl EnumAttributes { pub fn contains_error_attr(&self) -> bool { self.0.iter().any(|attr| attr.is_error()) } - - pub fn contains_non_exhaustive_attr(&self) -> bool { - self.0 - .iter() - .any(|attr| matches!(attr, Attribute::NonExhaustive)) - } } impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for EnumAttributes { @@ -238,10 +178,6 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for EnumAttributes { ) -> Result { let attrs = parse_attributes(weedle_attributes, |attr| match attr { Attribute::Error => Ok(()), - Attribute::NonExhaustive => Ok(()), - // Allow `[Enum]`, since we may be parsing an attribute list from an interface with the - // `[Enum]` attribute. - Attribute::Enum => Ok(()), _ => bail!(format!("{attr:?} not supported for enums")), })?; Ok(Self(attrs)) @@ -260,9 +196,8 @@ impl> TryFrom> for E /// Represents UDL attributes that might appear on a function. /// -/// This supports: -/// * `[Throws=ErrorName]` attribute for functions that can produce an error. -/// * `[Async] for async functions +/// This supports the `[Throws=ErrorName]` attribute for functions that +/// can produce an error. #[derive(Debug, Clone, Checksum, Default)] pub(super) struct FunctionAttributes(Vec); @@ -275,10 +210,6 @@ impl FunctionAttributes { _ => None, }) } - - pub(super) fn is_async(&self) -> bool { - self.0.iter().any(|attr| matches!(attr, Attribute::Async)) - } } impl FromIterator for FunctionAttributes { @@ -293,7 +224,7 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for FunctionAttribut weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>, ) -> Result { let attrs = parse_attributes(weedle_attributes, |attr| match attr { - Attribute::Throws(_) | Attribute::Async => Ok(()), + Attribute::Throws(_) => Ok(()), _ => bail!(format!("{attr:?} not supported for functions")), })?; Ok(Self(attrs)) @@ -363,25 +294,12 @@ impl InterfaceAttributes { self.0.iter().any(|attr| attr.is_error()) } - pub fn contains_trait(&self) -> bool { - self.0.iter().any(|attr| matches!(attr, Attribute::Trait)) - } - - pub fn contains_with_foreign(&self) -> bool { - self.0 - .iter() - .any(|attr| matches!(attr, Attribute::WithForeign)) - } - - pub fn object_impl(&self) -> Result { - Ok( - match (self.contains_trait(), self.contains_with_foreign()) { - (true, true) => ObjectImpl::CallbackTrait, - (true, false) => ObjectImpl::Trait, - (false, false) => ObjectImpl::Struct, - (false, true) => bail!("WithForeign can't be specified without Trait"), - }, - ) + pub fn object_impl(&self) -> ObjectImpl { + if self.0.iter().any(|attr| matches!(attr, Attribute::Trait)) { + ObjectImpl::Trait + } else { + ObjectImpl::Struct + } } pub fn get_traits(&self) -> Vec { self.0 @@ -403,7 +321,6 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for InterfaceAttribu Attribute::Enum => Ok(()), Attribute::Error => Ok(()), Attribute::Trait => Ok(()), - Attribute::WithForeign => Ok(()), Attribute::Traits(_) => Ok(()), _ => bail!(format!("{attr:?} not supported for interface definition")), })?; @@ -456,10 +373,6 @@ impl ConstructorAttributes { _ => None, }) } - - pub(super) fn is_async(&self) -> bool { - self.0.iter().any(|attr| matches!(attr, Attribute::Async)) - } } impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for ConstructorAttributes { @@ -470,7 +383,6 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for ConstructorAttri let attrs = parse_attributes(weedle_attributes, |attr| match attr { Attribute::Throws(_) => Ok(()), Attribute::Name(_) => Ok(()), - Attribute::Async => Ok(()), _ => bail!(format!("{attr:?} not supported for constructors")), })?; Ok(Self(attrs)) @@ -494,10 +406,6 @@ impl MethodAttributes { }) } - pub(super) fn is_async(&self) -> bool { - self.0.iter().any(|attr| matches!(attr, Attribute::Async)) - } - pub(super) fn get_self_by_arc(&self) -> bool { self.0 .iter() @@ -517,7 +425,8 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for MethodAttributes weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>, ) -> Result { let attrs = parse_attributes(weedle_attributes, |attr| match attr { - Attribute::SelfType(_) | Attribute::Throws(_) | Attribute::Async => Ok(()), + Attribute::SelfType(_) => Ok(()), + Attribute::Throws(_) => Ok(()), _ => bail!(format!("{attr:?} not supported for methods")), })?; Ok(Self(attrs)) @@ -589,18 +498,10 @@ impl TypedefAttributes { }) } - pub(super) fn rust_kind(&self) -> Option { - self.0.iter().find_map(|attr| match attr { - Attribute::Rust { kind, .. } => Some(*kind), - _ => None, - }) - } - pub(super) fn external_tagged(&self) -> Option { // If it was "exported" via a proc-macro the FfiConverter was not tagged. self.0.iter().find_map(|attr| match attr { Attribute::External { export, .. } => Some(!*export), - Attribute::Rust { .. } => Some(false), _ => None, }) } @@ -612,7 +513,7 @@ impl TryFrom<&weedle::attribute::ExtendedAttributeList<'_>> for TypedefAttribute weedle_attributes: &weedle::attribute::ExtendedAttributeList<'_>, ) -> Result { let attrs = parse_attributes(weedle_attributes, |attr| match attr { - Attribute::External { .. } | Attribute::Custom | Attribute::Rust { .. } => Ok(()), + Attribute::External { .. } | Attribute::Custom => Ok(()), _ => bail!(format!("{attr:?} not supported for typedefs")), })?; Ok(Self(attrs)) @@ -740,22 +641,14 @@ mod test { } #[test] - fn test_function_attributes() { + fn test_throws_attribute() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Throws=Error]").unwrap(); let attrs = FunctionAttributes::try_from(&node).unwrap(); assert!(matches!(attrs.get_throws_err(), Some("Error"))); - assert!(!attrs.is_async()); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap(); let attrs = FunctionAttributes::try_from(&node).unwrap(); assert!(attrs.get_throws_err().is_none()); - assert!(!attrs.is_async()); - - let (_, node) = - weedle::attribute::ExtendedAttributeList::parse("[Throws=Error, Async]").unwrap(); - let attrs = FunctionAttributes::try_from(&node).unwrap(); - assert!(matches!(attrs.get_throws_err(), Some("Error"))); - assert!(attrs.is_async()); } #[test] @@ -780,34 +673,22 @@ mod test { let attrs = MethodAttributes::try_from(&node).unwrap(); assert!(!attrs.get_self_by_arc()); assert!(matches!(attrs.get_throws_err(), Some("Error"))); - assert!(!attrs.is_async()); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap(); let attrs = MethodAttributes::try_from(&node).unwrap(); assert!(!attrs.get_self_by_arc()); assert!(attrs.get_throws_err().is_none()); - assert!(!attrs.is_async()); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Self=ByArc, Throws=Error]").unwrap(); let attrs = MethodAttributes::try_from(&node).unwrap(); assert!(attrs.get_self_by_arc()); assert!(attrs.get_throws_err().is_some()); - assert!(!attrs.is_async()); - - let (_, node) = - weedle::attribute::ExtendedAttributeList::parse("[Self=ByArc, Throws=Error, Async]") - .unwrap(); - let attrs = MethodAttributes::try_from(&node).unwrap(); - assert!(attrs.get_self_by_arc()); - assert!(attrs.get_throws_err().is_some()); - assert!(attrs.is_async()); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Self=ByArc]").unwrap(); let attrs = MethodAttributes::try_from(&node).unwrap(); assert!(attrs.get_self_by_arc()); assert!(attrs.get_throws_err().is_none()); - assert!(!attrs.is_async()); } #[test] @@ -829,11 +710,6 @@ mod test { let attrs = ConstructorAttributes::try_from(&node).unwrap(); assert!(matches!(attrs.get_throws_err(), Some("Error"))); assert!(matches!(attrs.get_name(), Some("MyFactory"))); - assert!(!attrs.is_async()); - - let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Async]").unwrap(); - let attrs = ConstructorAttributes::try_from(&node).unwrap(); - assert!(attrs.is_async()); } #[test] @@ -878,24 +754,15 @@ mod test { fn test_trait_attribute() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait]").unwrap(); let attrs = InterfaceAttributes::try_from(&node).unwrap(); - assert_eq!(attrs.object_impl().unwrap(), ObjectImpl::Trait); - - let (_, node) = - weedle::attribute::ExtendedAttributeList::parse("[Trait, WithForeign]").unwrap(); - let attrs = InterfaceAttributes::try_from(&node).unwrap(); - assert_eq!(attrs.object_impl().unwrap(), ObjectImpl::CallbackTrait); + assert_eq!(attrs.object_impl(), ObjectImpl::Trait); let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[]").unwrap(); let attrs = InterfaceAttributes::try_from(&node).unwrap(); - assert_eq!(attrs.object_impl().unwrap(), ObjectImpl::Struct); - - let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[WithForeign]").unwrap(); - let attrs = InterfaceAttributes::try_from(&node).unwrap(); - assert!(attrs.object_impl().is_err()) + assert_eq!(attrs.object_impl(), ObjectImpl::Struct); } #[test] - fn test_enum_attribute_on_interface() { + fn test_enum_attribute() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum]").unwrap(); let attrs = InterfaceAttributes::try_from(&node).unwrap(); assert!(matches!(attrs.contains_enum_attr(), true)); @@ -916,38 +783,6 @@ mod test { ); } - // Test parsing attributes for enum definitions - #[test] - fn test_enum_attributes() { - let (_, node) = - weedle::attribute::ExtendedAttributeList::parse("[Error, NonExhaustive]").unwrap(); - let attrs = EnumAttributes::try_from(&node).unwrap(); - assert!(attrs.contains_error_attr()); - assert!(attrs.contains_non_exhaustive_attr()); - - let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait]").unwrap(); - let err = EnumAttributes::try_from(&node).unwrap_err(); - assert_eq!(err.to_string(), "Trait not supported for enums"); - } - - // Test parsing attributes for interface definitions with the `[Enum]` attribute - #[test] - fn test_enum_attributes_from_interface() { - let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum]").unwrap(); - assert!(EnumAttributes::try_from(&node).is_ok()); - - let (_, node) = - weedle::attribute::ExtendedAttributeList::parse("[Enum, Error, NonExhaustive]") - .unwrap(); - let attrs = EnumAttributes::try_from(&node).unwrap(); - assert!(attrs.contains_error_attr()); - assert!(attrs.contains_non_exhaustive_attr()); - - let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Enum, Trait]").unwrap(); - let err = EnumAttributes::try_from(&node).unwrap_err(); - assert_eq!(err.to_string(), "Trait not supported for enums"); - } - #[test] fn test_other_attributes_not_supported_for_interfaces() { let (_, node) = weedle::attribute::ExtendedAttributeList::parse("[Trait, ByRef]").unwrap(); diff --git a/third_party/rust/uniffi_udl/src/collectors.rs b/third_party/rust/uniffi_udl/src/collectors.rs index de5489f5f9a4..6a91ab4a9327 100644 --- a/third_party/rust/uniffi_udl/src/collectors.rs +++ b/third_party/rust/uniffi_udl/src/collectors.rs @@ -5,7 +5,7 @@ //! # Collects metadata from UDL. use crate::attributes; -use crate::converters::{convert_docstring, APIConverter}; +use crate::converters::APIConverter; use crate::finder; use crate::resolver::TypeResolver; use anyhow::{bail, Result}; @@ -138,7 +138,6 @@ impl From for uniffi_meta::MetadataGroup { crate_name: value.types.module_path(), name: value.types.namespace, }, - namespace_docstring: value.types.namespace_docstring.clone(), items: value.items, } } @@ -172,13 +171,15 @@ impl APIBuilder for weedle::Definition<'_> { match self { weedle::Definition::Namespace(d) => d.process(ci)?, weedle::Definition::Enum(d) => { - let mut e: uniffi_meta::EnumMetadata = d.convert(ci)?; // We check if the enum represents an error... let attrs = attributes::EnumAttributes::try_from(d.attributes.as_ref())?; if attrs.contains_error_attr() { - e.forced_flatness = Some(true); + let e: uniffi_meta::ErrorMetadata = d.convert(ci)?; + ci.add_definition(e.into())?; + } else { + let e: uniffi_meta::EnumMetadata = d.convert(ci)?; + ci.add_definition(e.into())?; } - ci.add_definition(e.into())?; } weedle::Definition::Dictionary(d) => { let rec = d.convert(ci)?; @@ -186,9 +187,12 @@ impl APIBuilder for weedle::Definition<'_> { } weedle::Definition::Interface(d) => { let attrs = attributes::InterfaceAttributes::try_from(d.attributes.as_ref())?; - if attrs.contains_enum_attr() || attrs.contains_error_attr() { + if attrs.contains_enum_attr() { let e: uniffi_meta::EnumMetadata = d.convert(ci)?; ci.add_definition(e.into())?; + } else if attrs.contains_error_attr() { + let e: uniffi_meta::ErrorMetadata = d.convert(ci)?; + ci.add_definition(e.into())?; } else { let obj: uniffi_meta::ObjectMetadata = d.convert(ci)?; ci.add_definition(obj.into())?; @@ -214,7 +218,6 @@ impl APIBuilder for weedle::NamespaceDefinition<'_> { if self.identifier.0 != ci.types.namespace { bail!("duplicate namespace definition"); } - ci.types.namespace_docstring = self.docstring.as_ref().map(|v| convert_docstring(&v.0)); for func in self.members.body.convert(ci)? { ci.add_definition(func.into())?; } @@ -226,7 +229,6 @@ impl APIBuilder for weedle::NamespaceDefinition<'_> { pub(crate) struct TypeCollector { /// The unique prefix that we'll use for namespacing when exposing this component's API. pub namespace: String, - pub namespace_docstring: Option, pub crate_name: String, diff --git a/third_party/rust/uniffi_udl/src/converters/callables.rs b/third_party/rust/uniffi_udl/src/converters/callables.rs index dda3c3a3ce68..3e15bb8e02c2 100644 --- a/third_party/rust/uniffi_udl/src/converters/callables.rs +++ b/third_party/rust/uniffi_udl/src/converters/callables.rs @@ -5,7 +5,6 @@ use super::APIConverter; use crate::attributes::ArgumentAttributes; use crate::attributes::{ConstructorAttributes, FunctionAttributes, MethodAttributes}; -use crate::converters::convert_docstring; use crate::literal::convert_default_value; use crate::InterfaceCollector; use anyhow::{bail, Result}; @@ -42,7 +41,6 @@ impl APIConverter for weedle::argument::SingleArgument<'_> { name: self.identifier.0.to_string(), ty: type_, default: None, - docstring: None, }) } } @@ -91,7 +89,6 @@ impl APIConverter for weedle::namespace::OperationNamespaceMember<'_ Some(id) => id.0.to_string(), }; let attrs = FunctionAttributes::try_from(self.attributes.as_ref())?; - let is_async = attrs.is_async(); let throws = match attrs.get_throws_err() { None => None, Some(name) => match ci.get_type(name) { @@ -102,11 +99,10 @@ impl APIConverter for weedle::namespace::OperationNamespaceMember<'_ Ok(FnMetadata { module_path: ci.module_path(), name, - is_async, + is_async: false, return_type, inputs: self.args.body.list.convert(ci)?, throws, - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), checksum: None, }) } @@ -126,12 +122,10 @@ impl APIConverter for weedle::interface::ConstructorInterfa name: String::from(attributes.get_name().unwrap_or("new")), // We don't know the name of the containing `Object` at this point, fill it in later. self_name: Default::default(), - is_async: attributes.is_async(), // Also fill in checksum_fn_name later, since it depends on object_name inputs: self.args.body.list.convert(ci)?, throws, checksum: None, - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } @@ -146,7 +140,6 @@ impl APIConverter for weedle::interface::OperationInterfaceMembe } let return_type = ci.resolve_return_type_expression(&self.return_type)?; let attributes = MethodAttributes::try_from(self.attributes.as_ref())?; - let is_async = attributes.is_async(); let throws = match attributes.get_throws_err() { Some(name) => match ci.get_type(name) { @@ -171,13 +164,12 @@ impl APIConverter for weedle::interface::OperationInterfaceMembe }, // We don't know the name of the containing `Object` at this point, fill it in later. self_name: Default::default(), - is_async, + is_async: false, // not supported in UDL inputs: self.args.body.list.convert(ci)?, return_type, throws, takes_self_by_arc, checksum: None, - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } @@ -192,7 +184,6 @@ impl APIConverter for weedle::interface::OperationInterface } let return_type = ci.resolve_return_type_expression(&self.return_type)?; let attributes = MethodAttributes::try_from(self.attributes.as_ref())?; - let is_async = attributes.is_async(); let throws = match attributes.get_throws_err() { Some(name) => match ci.get_type(name) { @@ -217,13 +208,12 @@ impl APIConverter for weedle::interface::OperationInterface name } }, - is_async, + is_async: false, // not supported in udl inputs: self.args.body.list.convert(ci)?, return_type, throws, takes_self_by_arc, checksum: None, - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } diff --git a/third_party/rust/uniffi_udl/src/converters/enum_.rs b/third_party/rust/uniffi_udl/src/converters/enum_.rs index 1615a1a7ca89..a3e68fd23ebf 100644 --- a/third_party/rust/uniffi_udl/src/converters/enum_.rs +++ b/third_party/rust/uniffi_udl/src/converters/enum_.rs @@ -3,22 +3,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use super::APIConverter; -use crate::{attributes::EnumAttributes, converters::convert_docstring, InterfaceCollector}; +use crate::InterfaceCollector; use anyhow::{bail, Result}; -use uniffi_meta::{EnumMetadata, VariantMetadata}; +use uniffi_meta::{EnumMetadata, ErrorMetadata, VariantMetadata}; -// Note that we have 2 `APIConverter` impls here - one for the `enum` case -// (including an enum with `[Error]`), and one for the `[Error] interface` cas -// (which is still an enum, but with different "flatness" characteristics.) +// Note that we have four `APIConverter` impls here - one for the `enum` case, +// one for the `[Error] enum` case, and and one for the `[Enum] interface` case, +// and one for the `[Error] interface` case. impl APIConverter for weedle::EnumDefinition<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { - let attributes = EnumAttributes::try_from(self.attributes.as_ref())?; Ok(EnumMetadata { module_path: ci.module_path(), name: self.identifier.0.to_string(), - forced_flatness: None, - discr_type: None, variants: self .values .body @@ -26,15 +23,35 @@ impl APIConverter for weedle::EnumDefinition<'_> { .iter() .map::, _>(|v| { Ok(VariantMetadata { - name: v.value.0.to_string(), - discr: None, + name: v.0.to_string(), fields: vec![], - docstring: v.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) }) .collect::>>()?, - non_exhaustive: attributes.contains_non_exhaustive_attr(), - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), + }) + } +} + +impl APIConverter for weedle::EnumDefinition<'_> { + fn convert(&self, ci: &mut InterfaceCollector) -> Result { + Ok(ErrorMetadata::Enum { + enum_: EnumMetadata { + module_path: ci.module_path(), + name: self.identifier.0.to_string(), + variants: self + .values + .body + .list + .iter() + .map::, _>(|v| { + Ok(VariantMetadata { + name: v.0.to_string(), + fields: vec![], + }) + }) + .collect::>>()?, + }, + is_flat: true, }) } } @@ -44,11 +61,11 @@ impl APIConverter for weedle::InterfaceDefinition<'_> { if self.inheritance.is_some() { bail!("interface inheritance is not supported for enum interfaces"); } - let attributes = EnumAttributes::try_from(self.attributes.as_ref())?; + // We don't need to check `self.attributes` here; if calling code has dispatched + // to this impl then we already know there was an `[Enum]` attribute. Ok(EnumMetadata { module_path: ci.module_path(), name: self.identifier.0.to_string(), - forced_flatness: Some(false), variants: self .members .body @@ -61,15 +78,41 @@ impl APIConverter for weedle::InterfaceDefinition<'_> { ), }) .collect::>>()?, - discr_type: None, - non_exhaustive: attributes.contains_non_exhaustive_attr(), - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), // Enums declared using the `[Enum] interface` syntax might have variants with fields. //flat: false, }) } } +impl APIConverter for weedle::InterfaceDefinition<'_> { + fn convert(&self, ci: &mut InterfaceCollector) -> Result { + if self.inheritance.is_some() { + bail!("interface inheritance is not supported for enum interfaces"); + } + // We don't need to check `self.attributes` here; callers have already checked them + // to work out which version to dispatch to. + Ok(ErrorMetadata::Enum { + enum_: EnumMetadata { + module_path: ci.module_path(), + name: self.identifier.0.to_string(), + variants: self + .members + .body + .iter() + .map::, _>(|member| match member { + weedle::interface::InterfaceMember::Operation(t) => Ok(t.convert(ci)?), + _ => bail!( + "interface member type {:?} not supported in enum interface", + member + ), + }) + .collect::>>()?, + }, + is_flat: false, + }) + } +} + #[cfg(test)] mod test { use super::*; diff --git a/third_party/rust/uniffi_udl/src/converters/interface.rs b/third_party/rust/uniffi_udl/src/converters/interface.rs index ef9bdd954069..58e6a9c8a09f 100644 --- a/third_party/rust/uniffi_udl/src/converters/interface.rs +++ b/third_party/rust/uniffi_udl/src/converters/interface.rs @@ -4,7 +4,7 @@ use super::APIConverter; use crate::attributes::InterfaceAttributes; -use crate::{converters::convert_docstring, InterfaceCollector}; +use crate::InterfaceCollector; use anyhow::{bail, Result}; use std::collections::HashSet; use uniffi_meta::{ @@ -23,7 +23,7 @@ impl APIConverter for weedle::InterfaceDefinition<'_> { }; let object_name = self.identifier.0; - let object_impl = attributes.object_impl()?; + let object_impl = attributes.object_impl(); // Convert each member into a constructor or method, guarding against duplicate names. // They get added to the ci and aren't carried in ObjectMetadata. let mut member_names = HashSet::new(); @@ -70,7 +70,6 @@ impl APIConverter for weedle::InterfaceDefinition<'_> { throws: None, takes_self_by_arc: false, checksum: None, - docstring: None, }) }; // Trait methods are in the Metadata. @@ -131,7 +130,6 @@ impl APIConverter for weedle::InterfaceDefinition<'_> { module_path: ci.module_path(), name: object_name.to_string(), imp: object_impl, - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } diff --git a/third_party/rust/uniffi_udl/src/converters/mod.rs b/third_party/rust/uniffi_udl/src/converters/mod.rs index 195d9cc0b7b4..7a2d22ac42e1 100644 --- a/third_party/rust/uniffi_udl/src/converters/mod.rs +++ b/third_party/rust/uniffi_udl/src/converters/mod.rs @@ -29,11 +29,6 @@ pub(crate) trait APIConverter { fn convert(&self, ci: &mut InterfaceCollector) -> Result; } -// Convert UDL docstring into metadata docstring -pub(crate) fn convert_docstring(docstring: &str) -> String { - textwrap::dedent(docstring) -} - /// Convert a list of weedle items into a list of `InterfaceCollector` items, /// by doing a direct item-by-item mapping. impl> APIConverter> for Vec { @@ -77,7 +72,6 @@ impl APIConverter for weedle::interface::OperationInterfaceMemb }; Ok(VariantMetadata { name, - discr: None, fields: self .args .body @@ -85,7 +79,6 @@ impl APIConverter for weedle::interface::OperationInterfaceMemb .iter() .map(|arg| arg.convert(ci)) .collect::>>()?, - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } @@ -102,7 +95,6 @@ impl APIConverter for weedle::DictionaryDefinition<'_> { module_path: ci.module_path(), name: self.identifier.0.to_string(), fields: self.members.body.convert(ci)?, - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } @@ -121,7 +113,6 @@ impl APIConverter for weedle::dictionary::DictionaryMember<'_> { name: self.identifier.0.to_string(), ty: type_, default, - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } @@ -159,7 +150,6 @@ impl APIConverter for weedle::CallbackInterfaceDefini Ok(CallbackInterfaceMetadata { module_path: ci.module_path(), name: object_name.to_string(), - docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } diff --git a/third_party/rust/uniffi_udl/src/finder.rs b/third_party/rust/uniffi_udl/src/finder.rs index 259557ad07e4..0c4c187dc010 100644 --- a/third_party/rust/uniffi_udl/src/finder.rs +++ b/third_party/rust/uniffi_udl/src/finder.rs @@ -22,8 +22,8 @@ use std::convert::TryFrom; use anyhow::{bail, Result}; use super::TypeCollector; -use crate::attributes::{InterfaceAttributes, RustKind, TypedefAttributes}; -use uniffi_meta::{ObjectImpl, Type}; +use crate::attributes::{InterfaceAttributes, TypedefAttributes}; +use uniffi_meta::Type; /// Trait to help with an early "type discovery" phase when processing the UDL. /// @@ -75,7 +75,7 @@ impl TypeFinder for weedle::InterfaceDefinition<'_> { Type::Object { name, module_path: types.module_path(), - imp: attrs.object_impl()?, + imp: attrs.object_impl(), }, ) } @@ -111,6 +111,7 @@ impl TypeFinder for weedle::EnumDefinition<'_> { impl TypeFinder for weedle::TypedefDefinition<'_> { fn add_type_definitions_to(&self, types: &mut TypeCollector) -> Result<()> { + let name = self.identifier.0; let attrs = TypedefAttributes::try_from(self.attributes.as_ref())?; // If we wanted simple `typedef`s, it would be as easy as: // > let t = types.resolve_type_expression(&self.type_)?; @@ -121,52 +122,29 @@ impl TypeFinder for weedle::TypedefDefinition<'_> { // `FfiConverter` implementation. let builtin = types.resolve_type_expression(&self.type_)?; types.add_type_definition( - self.identifier.0, + name, Type::Custom { module_path: types.module_path(), - name: self.identifier.0.to_string(), + name: name.to_string(), builtin: builtin.into(), }, ) } else { - let module_path = types.module_path(); - let name = self.identifier.0.to_string(); - let ty = match attrs.rust_kind() { - Some(RustKind::Object) => Type::Object { - module_path, - name, - imp: ObjectImpl::Struct, - }, - Some(RustKind::Trait) => Type::Object { - module_path, - name, - imp: ObjectImpl::Trait, - }, - Some(RustKind::CallbackTrait) => Type::Object { - module_path, - name, - imp: ObjectImpl::CallbackTrait, - }, - Some(RustKind::Record) => Type::Record { module_path, name }, - Some(RustKind::Enum) => Type::Enum { module_path, name }, - Some(RustKind::CallbackInterface) => Type::CallbackInterface { module_path, name }, - // must be external - None => { - let kind = attrs.external_kind().expect("External missing kind"); - let tagged = attrs.external_tagged().expect("External missing tagged"); - Type::External { - name, - namespace: "".to_string(), // we don't know this yet - module_path: attrs.get_crate_name(), - kind, - tagged, - } - } - }; + let kind = attrs.external_kind().expect("External missing"); + let tagged = attrs.external_tagged().expect("External missing"); // A crate which can supply an `FfiConverter`. // We don't reference `self._type`, so ideally we could insist on it being // the literal 'extern' but that's tricky - types.add_type_definition(self.identifier.0, ty) + types.add_type_definition( + name, + Type::External { + name: name.to_string(), + namespace: "".to_string(), // we don't know this yet + module_path: attrs.get_crate_name(), + kind, + tagged, + }, + ) } } } @@ -174,7 +152,7 @@ impl TypeFinder for weedle::TypedefDefinition<'_> { impl TypeFinder for weedle::CallbackInterfaceDefinition<'_> { fn add_type_definitions_to(&self, types: &mut TypeCollector) -> Result<()> { if self.attributes.is_some() { - bail!("no callback interface attributes are currently supported"); + bail!("no typedef attributes are currently supported"); } let name = self.identifier.0.to_string(); types.add_type_definition( diff --git a/third_party/rust/uniffi_udl/src/lib.rs b/third_party/rust/uniffi_udl/src/lib.rs index a9dad5d6c562..5e6e72a7f77d 100644 --- a/third_party/rust/uniffi_udl/src/lib.rs +++ b/third_party/rust/uniffi_udl/src/lib.rs @@ -6,7 +6,7 @@ //! //! This library is dedicated to parsing a string in a webidl syntax, as described by //! weedle and with our own custom take on the attributes etc, pushing the boundaries -//! of that syntax to describe a uniffi `MetadataGroup`. +//! of that syntax to describe a uniffi `MetatadataGroup`. //! //! The output of this module is consumed by uniffi_bindgen to generate stuff. diff --git a/third_party/rust/uniffi_udl/src/literal.rs b/third_party/rust/uniffi_udl/src/literal.rs index 5fbf02264459..78f254425491 100644 --- a/third_party/rust/uniffi_udl/src/literal.rs +++ b/third_party/rust/uniffi_udl/src/literal.rs @@ -84,10 +84,8 @@ pub(super) fn convert_default_value( (weedle::literal::DefaultValue::String(s), Type::Enum { .. }) => { Literal::Enum(s.0.to_string(), type_.clone()) } - (weedle::literal::DefaultValue::Null(_), Type::Optional { .. }) => Literal::None, - (_, Type::Optional { inner_type, .. }) => Literal::Some { - inner: Box::new(convert_default_value(default_value, inner_type)?), - }, + (weedle::literal::DefaultValue::Null(_), Type::Optional { .. }) => Literal::Null, + (_, Type::Optional { inner_type, .. }) => convert_default_value(default_value, inner_type)?, // We'll ensure the type safety in the convert_* number methods. (weedle::literal::DefaultValue::Integer(i), _) => convert_integer(i, type_)?, @@ -146,7 +144,7 @@ mod test { inner_type: Box::new(Type::String) } )?, - Literal::None + Literal::Null )); Ok(()) } diff --git a/third_party/rust/uniffi_udl/src/resolver.rs b/third_party/rust/uniffi_udl/src/resolver.rs index ea98cd7a9989..14a7a4c6f1bf 100644 --- a/third_party/rust/uniffi_udl/src/resolver.rs +++ b/third_party/rust/uniffi_udl/src/resolver.rs @@ -209,6 +209,7 @@ pub(crate) fn resolve_builtin_type(name: &str) -> Option { "f64" => Some(Type::Float64), "timestamp" => Some(Type::Timestamp), "duration" => Some(Type::Duration), + "ForeignExecutor" => Some(Type::ForeignExecutor), _ => None, } } diff --git a/third_party/rust/webext-storage/.cargo-checksum.json b/third_party/rust/webext-storage/.cargo-checksum.json index 25f2af17bf21..98fa4d6a227b 100644 --- a/third_party/rust/webext-storage/.cargo-checksum.json +++ b/third_party/rust/webext-storage/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"b20c30e7d9ae0460d04b744d5a9274985ded6e5b9ed0262b914553ca71425821","README.md":"1fd617294339930ee1ad5172377648b268cce0216fc3971facbfe7c6839e9ab1","build.rs":"92f7d380f3d8fab1e6d80276915af57192e276321d132a5f800ea4520e9cb469","sql/create_schema.sql":"a17311a407ec10e033886b7125da4c8b84bc6d761f6b28edc9594de430e1d964","sql/create_sync_temp_tables.sql":"860ede362c94feb47d85522553fa2852f9bdb9f9b025d6438dd5dee3d4acd527","sql/tests/create_schema_v1.sql":"77cf0c90eaac3e1aea626537147e1b8ec349b68d6076c92fa7ae402aac613050","src/api.rs":"6fe362e4f437def2ad2249de385cca8f0d1d5d67679240351e9f57523fefe5e7","src/db.rs":"b95024c1d8f36a76a6f3098acea5a82bc49de144a24cdc280ed38e9bcc8e772b","src/error.rs":"6437e9a0edefac2707af85eef13bdbfcd53a84d7aa7859599155d10451d42361","src/ffi.rs":"f66a81393bebe7a4b7e7960cb426df106ff1f02bfebcaa6e335b4b8b56c5c936","src/lib.rs":"ab25e7c6ea67fb905fe6dad866c0d2c462b1e93bcff283db947513aeabbb2d73","src/migration.rs":"8d92f82b2ba38e1039fd054c8c75078a6b896a0d3cdc1a52571456b25a32c9c3","src/schema.rs":"d8dd8f66cad71e3e369722734e0d5d16fd9423d5f6a5abba1854a27e1e814724","src/store.rs":"d208689c46fb97cd2c60a0c610ba1998a7132fb50fffa2eefa1d6b169b7c34f0","src/sync/bridge.rs":"996de05beb2904f84b3cbfc9ef85c4844078fdb4867d9068390d496156bee614","src/sync/incoming.rs":"dd77c64e2ade4f39cba258decab6d3db8ad0b5f513aa018efbd56b9869a021d9","src/sync/mod.rs":"bd1bc5c428dfda6aee7efe53b6e74b8015da5129a303638a21ca8d63516e4061","src/sync/outgoing.rs":"dacb77b956f2546fd60a89367927a199d9b662b17201d0781145f7405b61fdce","src/sync/sync_tests.rs":"f3846ca7e463315ba9788826613b987ddcff7b21672ff257a98769ee94f4191a","src/webext-storage.udl":"0341d431ba837cf64ea210ef6157010c6664a0b5a194e89acb0414938636b391","uniffi.toml":"beeec89c2f877eb89be0090dc304dbc7c74e787385e7459bad78c6165bb66791"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"a11f7fbc29c375034289e7bdd11da4aadac9cb2d939a4f2e5dc61aaea35cf465","README.md":"1fd617294339930ee1ad5172377648b268cce0216fc3971facbfe7c6839e9ab1","build.rs":"92f7d380f3d8fab1e6d80276915af57192e276321d132a5f800ea4520e9cb469","sql/create_schema.sql":"a17311a407ec10e033886b7125da4c8b84bc6d761f6b28edc9594de430e1d964","sql/create_sync_temp_tables.sql":"860ede362c94feb47d85522553fa2852f9bdb9f9b025d6438dd5dee3d4acd527","sql/tests/create_schema_v1.sql":"77cf0c90eaac3e1aea626537147e1b8ec349b68d6076c92fa7ae402aac613050","src/api.rs":"6fe362e4f437def2ad2249de385cca8f0d1d5d67679240351e9f57523fefe5e7","src/db.rs":"b95024c1d8f36a76a6f3098acea5a82bc49de144a24cdc280ed38e9bcc8e772b","src/error.rs":"6437e9a0edefac2707af85eef13bdbfcd53a84d7aa7859599155d10451d42361","src/ffi.rs":"f66a81393bebe7a4b7e7960cb426df106ff1f02bfebcaa6e335b4b8b56c5c936","src/lib.rs":"ab25e7c6ea67fb905fe6dad866c0d2c462b1e93bcff283db947513aeabbb2d73","src/migration.rs":"8d92f82b2ba38e1039fd054c8c75078a6b896a0d3cdc1a52571456b25a32c9c3","src/schema.rs":"d8dd8f66cad71e3e369722734e0d5d16fd9423d5f6a5abba1854a27e1e814724","src/store.rs":"d208689c46fb97cd2c60a0c610ba1998a7132fb50fffa2eefa1d6b169b7c34f0","src/sync/bridge.rs":"996de05beb2904f84b3cbfc9ef85c4844078fdb4867d9068390d496156bee614","src/sync/incoming.rs":"dd77c64e2ade4f39cba258decab6d3db8ad0b5f513aa018efbd56b9869a021d9","src/sync/mod.rs":"bd1bc5c428dfda6aee7efe53b6e74b8015da5129a303638a21ca8d63516e4061","src/sync/outgoing.rs":"dacb77b956f2546fd60a89367927a199d9b662b17201d0781145f7405b61fdce","src/sync/sync_tests.rs":"f3846ca7e463315ba9788826613b987ddcff7b21672ff257a98769ee94f4191a","src/webext-storage.udl":"0341d431ba837cf64ea210ef6157010c6664a0b5a194e89acb0414938636b391","uniffi.toml":"beeec89c2f877eb89be0090dc304dbc7c74e787385e7459bad78c6165bb66791"},"package":null} \ No newline at end of file diff --git a/third_party/rust/webext-storage/Cargo.toml b/third_party/rust/webext-storage/Cargo.toml index 8306a25dd2a5..c3f9b170df4e 100644 --- a/third_party/rust/webext-storage/Cargo.toml +++ b/third_party/rust/webext-storage/Cargo.toml @@ -28,7 +28,7 @@ serde = "1" serde_derive = "1" serde_json = "1" thiserror = "1.0" -uniffi = "0.27.1" +uniffi = "0.25.2" [dependencies.error-support] path = "../support/error" @@ -78,7 +78,7 @@ path = "../support/sql" path = "../support/rc_crypto/nss/nss_build_common" [build-dependencies.uniffi] -version = "0.27.1" +version = "0.25.2" features = ["build"] [features] diff --git a/third_party/rust/weedle2/.cargo-checksum.json b/third_party/rust/weedle2/.cargo-checksum.json dissimilarity index 61% index 13a9d357d529..9eb63aa3c164 100644 --- a/third_party/rust/weedle2/.cargo-checksum.json +++ b/third_party/rust/weedle2/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"cd75893e67b7ed5e1ee200efddc874a7d235a7275b3d9bbadd728d47a5d5b8c6","LICENSE.md":"467e2e44913e850ca4fb6760fa3b78ffefda2a21688a6b1e26a8b706963669eb","README.md":"b18a5a8af93ebf01f28b3ec637e64fb0bd21d556e356984974d0031f6eeda47a","release.toml":"fce2a51533478f7e7d663b11ac69676323856780adf8af158ce213c9dbc86c75","src/argument.rs":"aa7a119364de0a1f91b00db6cffb0a7b2ee73e0fb79a764211165ccebed56dc8","src/attribute.rs":"b3577059be9c1262d3360b4b4cf4cc6cb052251e5b9d64906fb40fc5e925da69","src/common.rs":"c0ae3236856bbe9917326ac9769e2fe15283cd4d1a0216aafcea3bc03ad724cc","src/dictionary.rs":"d0c9a40e694eb563d7d8307d36a3f9a3be1766846bdfa809d614a6e1e9e149d1","src/interface.rs":"352f7773e9e3870fa61efdb2b737d777a34def1eb8301ec66f7c416b31d5e88b","src/lib.rs":"95c6b27082959165f3899b4a5a520b10fbcab80dcf94ecf030aba74df0748203","src/literal.rs":"16d44ae36f893c3b2d8d807921b31b992b7e3ce7d1729913b4f392f52db44f9e","src/macros.rs":"2f24c285806c863fd9dc65534479d36961d9666ca5e11c9137f2ce2659a712b6","src/mixin.rs":"d65ff3a49615dabdf3f7845723f01ae730a83c8ef5bdd9a945d35149a9ef2858","src/namespace.rs":"417a9a6cb26efc8f84bd84e59c6ae7378502f920a76738b355e8c905e62efed8","src/term.rs":"049514b2b44f1bcb5c23d225d3bb0a6135892a5660049c694681c5b99d47d8e7","src/types.rs":"0fe236336e71079c88ae4848624af29c87dd16266ba36c30a0d47e7dc4d33587","src/whitespace.rs":"9b58cfc0a4b8667a26ff3d4dcd424a3d00bf23abab4dd0d286318cb18bd77a13"},"package":"998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e"} \ No newline at end of file +{"files":{"Cargo.toml":"1c9da38b083da061c42208494a1161d95938a524054f95b39097248da32ebfd0","LICENSE.md":"467e2e44913e850ca4fb6760fa3b78ffefda2a21688a6b1e26a8b706963669eb","README.md":"32092d702b93e9cc8d95fbcad1e30e315882a55496ad90a855ea575dc47aa7d4","release.toml":"fce2a51533478f7e7d663b11ac69676323856780adf8af158ce213c9dbc86c75","src/argument.rs":"aa7a119364de0a1f91b00db6cffb0a7b2ee73e0fb79a764211165ccebed56dc8","src/attribute.rs":"b3577059be9c1262d3360b4b4cf4cc6cb052251e5b9d64906fb40fc5e925da69","src/common.rs":"9d781dacc2582ac375f2c3b6b22bcb01add4a63db525d18ebb3af6fe633a311e","src/dictionary.rs":"be209d70b0db33acf753ca63998a63dd37a9d4b193583a1490782781360c2d01","src/interface.rs":"bd2f32bfbcab2167f056fabbf92da9852300141ffc80d9542c6e1bbea9d521ac","src/lib.rs":"42466a14426416dc0d3500842c86fe00471c2d73be6df823c3e05ba0e4572d20","src/literal.rs":"16d44ae36f893c3b2d8d807921b31b992b7e3ce7d1729913b4f392f52db44f9e","src/macros.rs":"2f24c285806c863fd9dc65534479d36961d9666ca5e11c9137f2ce2659a712b6","src/mixin.rs":"d65ff3a49615dabdf3f7845723f01ae730a83c8ef5bdd9a945d35149a9ef2858","src/namespace.rs":"fe6b406c2ab8bd904d0dff8a12321c77f4082ab364559e578e53ab415c8541fa","src/term.rs":"049514b2b44f1bcb5c23d225d3bb0a6135892a5660049c694681c5b99d47d8e7","src/types.rs":"0fe236336e71079c88ae4848624af29c87dd16266ba36c30a0d47e7dc4d33587","src/whitespace.rs":"552ebc98857859e8714e06bb25681ceab6052d009e00f55cceda0d4fb3c4f059"},"package":"2e79c5206e1f43a2306fd64bdb95025ee4228960f2e6c5a8b173f3caaf807741"} \ No newline at end of file diff --git a/third_party/rust/weedle2/Cargo.toml b/third_party/rust/weedle2/Cargo.toml index 66703cf60733..072d3f9a2a65 100644 --- a/third_party/rust/weedle2/Cargo.toml +++ b/third_party/rust/weedle2/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2021" name = "weedle2" -version = "5.0.0" +version = "4.0.0" authors = [ "Sharad Chand ", "Jan-Erik Rediger ", @@ -21,9 +21,10 @@ exclude = ["tests"] description = "A WebIDL Parser" homepage = "https://github.com/mozilla/uniffi-rs/tree/main/weedle2" documentation = "https://docs.rs/weedle2" -readme = "README.md" +readme = "./README.md" license = "MIT" repository = "https://github.com/mozilla/uniffi-rs" +resolver = "2" [lib] name = "weedle" diff --git a/third_party/rust/weedle2/README.md b/third_party/rust/weedle2/README.md index 88e4cec01726..889dc0da193c 100644 --- a/third_party/rust/weedle2/README.md +++ b/third_party/rust/weedle2/README.md @@ -28,7 +28,7 @@ Parses valid WebIDL definitions & produces a data structure starting from ```toml [dependencies] -weedle2 = "5.0.0" +weedle2 = "4.0.0" ``` ### `src/main.rs` diff --git a/third_party/rust/weedle2/src/common.rs b/third_party/rust/weedle2/src/common.rs index d36f6e5438b0..fadf89ba8b7c 100644 --- a/third_party/rust/weedle2/src/common.rs +++ b/third_party/rust/weedle2/src/common.rs @@ -33,18 +33,6 @@ impl<'a, T: Parse<'a>, U: Parse<'a>, V: Parse<'a>> Parse<'a> for (T, U, V) { parser!(nom::sequence::tuple((T::parse, U::parse, V::parse))); } -pub(crate) fn docstring(input: &str) -> IResult<&str, String> { - nom::multi::many1(nom::sequence::preceded( - nom::character::complete::multispace0, - nom::sequence::delimited( - nom::bytes::complete::tag("///"), - nom::bytes::complete::take_until("\n"), - nom::bytes::complete::tag("\n"), - ), - ))(input) - .map(|io| (io.0, io.1.join("\n"))) -} - ast_types! { /// Parses `( body )` #[derive(Copy, Default)] @@ -115,11 +103,6 @@ ast_types! { assign: term!(=), value: DefaultValue<'a>, } - - /// Represents consecutive comment lines starting with `///`, joined by `\n`. - struct Docstring( - String = docstring, - ) } #[cfg(test)] @@ -228,32 +211,4 @@ mod test { Identifier; 0 == "hello"; }); - - test!(should_parse_docstring { "///hello world\n" => - ""; - Docstring; - 0 == "hello world"; - }); - - test!(should_parse_multiline_docstring { "///hello\n///world\n" => - ""; - Docstring; - 0 == "hello\nworld"; - }); - - test!(should_parse_multiline_indented_docstring { "///hello\n ///world\n" => - ""; - Docstring; - 0 == "hello\nworld"; - }); - - test!(should_not_parse_docstring_with_comments { "///hello\n//comment1\n///world\n" => - "//comment1\n///world\n"; - Docstring; - 0 == "hello"; - }); - - test!(err should_not_parse_not_docstring { "" => - Docstring - }); } diff --git a/third_party/rust/weedle2/src/dictionary.rs b/third_party/rust/weedle2/src/dictionary.rs index b775d526dca1..3c9b23cac556 100644 --- a/third_party/rust/weedle2/src/dictionary.rs +++ b/third_party/rust/weedle2/src/dictionary.rs @@ -1,5 +1,5 @@ use crate::attribute::ExtendedAttributeList; -use crate::common::{Default, Docstring, Identifier}; +use crate::common::{Default, Identifier}; use crate::types::Type; /// Parses dictionary members @@ -8,7 +8,6 @@ pub type DictionaryMembers<'a> = Vec>; ast_types! { /// Parses dictionary member `[attributes]? required? type identifier ( = default )?;` struct DictionaryMember<'a> { - docstring: Option, attributes: Option>, required: Option, type_: Type<'a>, diff --git a/third_party/rust/weedle2/src/interface.rs b/third_party/rust/weedle2/src/interface.rs index ab3c10d3c3cc..5e30909c3894 100644 --- a/third_party/rust/weedle2/src/interface.rs +++ b/third_party/rust/weedle2/src/interface.rs @@ -1,6 +1,6 @@ use crate::argument::ArgumentList; use crate::attribute::ExtendedAttributeList; -use crate::common::{Docstring, Generics, Identifier, Parenthesized}; +use crate::common::{Generics, Identifier, Parenthesized}; use crate::literal::ConstValue; use crate::types::{AttributedType, ConstType, ReturnType}; @@ -41,7 +41,6 @@ ast_types! { /// /// (( )) means ( ) chars Constructor(struct ConstructorInterfaceMember<'a> { - docstring: Option, attributes: Option>, constructor: term!(constructor), args: Parenthesized>, @@ -51,7 +50,6 @@ ast_types! { /// /// (( )) means ( ) chars Operation(struct OperationInterfaceMember<'a> { - docstring: Option, attributes: Option>, modifier: Option, special: Option, diff --git a/third_party/rust/weedle2/src/lib.rs b/third_party/rust/weedle2/src/lib.rs index 71ab7c33b5ba..610a34fa143d 100644 --- a/third_party/rust/weedle2/src/lib.rs +++ b/third_party/rust/weedle2/src/lib.rs @@ -23,7 +23,7 @@ use self::argument::ArgumentList; use self::attribute::ExtendedAttributeList; -use self::common::{Braced, Docstring, Identifier, Parenthesized, PunctuatedNonEmpty}; +use self::common::{Braced, Identifier, Parenthesized, PunctuatedNonEmpty}; use self::dictionary::DictionaryMembers; use self::interface::{Inheritance, InterfaceMembers}; use self::literal::StringLit; @@ -109,7 +109,6 @@ ast_types! { }), /// Parses `[attributes]? callback interface identifier ( : inheritance )? { members };` CallbackInterface(struct CallbackInterfaceDefinition<'a> { - docstring: Option, attributes: Option>, callback: term!(callback), interface: term!(interface), @@ -120,7 +119,6 @@ ast_types! { }), /// Parses `[attributes]? interface identifier ( : inheritance )? { members };` Interface(struct InterfaceDefinition<'a> { - docstring: Option, attributes: Option>, interface: term!(interface), identifier: Identifier<'a>, @@ -139,7 +137,6 @@ ast_types! { }), /// Parses `[attributes]? namespace identifier { members };` Namespace(struct NamespaceDefinition<'a> { - docstring: Option, attributes: Option>, namespace: term!(namespace), identifier: Identifier<'a>, @@ -148,7 +145,6 @@ ast_types! { }), /// Parses `[attributes]? dictionary identifier ( : inheritance )? { members };` Dictionary(struct DictionaryDefinition<'a> { - docstring: Option, attributes: Option>, dictionary: term!(dictionary), identifier: Identifier<'a>, @@ -195,7 +191,6 @@ ast_types! { }), /// Parses `[attributes]? enum identifier { values };` Enum(struct EnumDefinition<'a> { - docstring: Option, attributes: Option>, enum_: term!(enum), identifier: Identifier<'a>, @@ -229,15 +224,8 @@ ast_types! { } } -ast_types! { - struct EnumVariant<'a> { - docstring: Option, - value: StringLit<'a>, - } -} - /// Parses a non-empty enum value list -pub type EnumValueList<'a> = PunctuatedNonEmpty, term!(,)>; +pub type EnumValueList<'a> = PunctuatedNonEmpty, term!(,)>; #[cfg(test)] mod test { diff --git a/third_party/rust/weedle2/src/namespace.rs b/third_party/rust/weedle2/src/namespace.rs index 60673cdcec31..ed28573218dc 100644 --- a/third_party/rust/weedle2/src/namespace.rs +++ b/third_party/rust/weedle2/src/namespace.rs @@ -1,6 +1,6 @@ use crate::argument::ArgumentList; use crate::attribute::ExtendedAttributeList; -use crate::common::{Docstring, Identifier, Parenthesized}; +use crate::common::{Identifier, Parenthesized}; use crate::types::{AttributedType, ReturnType}; /// Parses namespace members declaration @@ -13,7 +13,6 @@ ast_types! { /// /// (( )) means ( ) chars Operation(struct OperationNamespaceMember<'a> { - docstring: Option, attributes: Option>, return_type: ReturnType<'a>, identifier: Option>, @@ -22,7 +21,6 @@ ast_types! { }), /// Parses `[attribute]? readonly attributetype type identifier;` Attribute(struct AttributeNamespaceMember<'a> { - docstring: Option, attributes: Option>, readonly: term!(readonly), attribute: term!(attribute), diff --git a/third_party/rust/weedle2/src/whitespace.rs b/third_party/rust/weedle2/src/whitespace.rs index 4be3ca43e891..336e4784e103 100644 --- a/third_party/rust/weedle2/src/whitespace.rs +++ b/third_party/rust/weedle2/src/whitespace.rs @@ -7,7 +7,6 @@ pub(crate) fn sp(input: &str) -> IResult<&str, &str> { (), nom::sequence::tuple(( nom::bytes::complete::tag("//"), - nom::combinator::not(nom::bytes::complete::tag("/")), nom::bytes::complete::take_until("\n"), nom::bytes::complete::tag("\n"), )), diff --git a/toolkit/components/glean/Cargo.toml b/toolkit/components/glean/Cargo.toml index ba563f514a3a..98b8d8a95b2b 100644 --- a/toolkit/components/glean/Cargo.toml +++ b/toolkit/components/glean/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" license = "MPL-2.0" [dependencies] -glean = "59.0.0" +glean = "58.1.0" log = "0.4" nserror = { path = "../../../xpcom/rust/nserror" } nsstring = { path = "../../../xpcom/rust/nsstring" } diff --git a/toolkit/components/glean/api/Cargo.toml b/toolkit/components/glean/api/Cargo.toml index af507f499f05..dc688dc41efa 100644 --- a/toolkit/components/glean/api/Cargo.toml +++ b/toolkit/components/glean/api/Cargo.toml @@ -9,7 +9,7 @@ license = "MPL-2.0" [dependencies] bincode = "1.0" chrono = "0.4.10" -glean = "59.0.0" +glean = "58.1.0" inherent = "1.0.0" log = "0.4" nsstring = { path = "../../../../xpcom/rust/nsstring", optional = true } diff --git a/toolkit/components/glean/api/src/common_test.rs b/toolkit/components/glean/api/src/common_test.rs index 1e02bfccf4cc..3c8c2c71e1cc 100644 --- a/toolkit/components/glean/api/src/common_test.rs +++ b/toolkit/components/glean/api/src/common_test.rs @@ -43,7 +43,6 @@ fn setup_glean(tempdir: Option) -> tempfile::TempDir { rate_limit: None, enable_event_timestamps: false, experimentation_id: None, - enable_internal_pings: true, }; let client_info = glean::ClientInfoMetrics { diff --git a/toolkit/components/glean/src/init/mod.rs b/toolkit/components/glean/src/init/mod.rs index 6c5772ae7f3a..f430cd73840d 100644 --- a/toolkit/components/glean/src/init/mod.rs +++ b/toolkit/components/glean/src/init/mod.rs @@ -184,7 +184,6 @@ fn build_configuration( rate_limit, enable_event_timestamps, experimentation_id: None, - enable_internal_pings: true, }; Ok((configuration, client_info)) diff --git a/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml b/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml index 5ef165dc73a5..32232c64b97d 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml +++ b/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml @@ -15,7 +15,7 @@ clap = { version = "4", default-features = false, features = ["std", "derive", " extend = "1.1" heck = "0.4" uniffi = { workspace = true } -uniffi_bindgen = { workspace = true } +uniffi_bindgen = "0.25" serde = "1" toml = "0.5" camino = "1.0.8" diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRelevancy.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRelevancy.sys.mjs index 20a48a70e3db..653164ea50fb 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRelevancy.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRelevancy.sys.mjs @@ -334,7 +334,7 @@ export class RelevancyStore { throw e; } return UniFFIScaffolding.callAsync( - 1, // relevancy:uniffi_relevancy_fn_constructor_relevancystore_new + 0, // relevancy:uniffi_relevancy_fn_constructor_relevancystore_new FfiConverterString.lower(dbpath), ) } @@ -349,7 +349,7 @@ export class RelevancyStore { const liftError = (data) => FfiConverterTypeRelevancyApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 2, // relevancy:uniffi_relevancy_fn_method_relevancystore_calculate_metrics + 1, // relevancy:uniffi_relevancy_fn_method_relevancystore_calculate_metrics FfiConverterTypeRelevancyStore.lower(this), ) } @@ -373,7 +373,7 @@ export class RelevancyStore { throw e; } return UniFFIScaffolding.callAsync( - 3, // relevancy:uniffi_relevancy_fn_method_relevancystore_ingest + 2, // relevancy:uniffi_relevancy_fn_method_relevancystore_ingest FfiConverterTypeRelevancyStore.lower(this), FfiConverterSequencestring.lower(topUrls), ) @@ -390,7 +390,7 @@ export class RelevancyStore { const liftError = (data) => FfiConverterTypeRelevancyApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 4, // relevancy:uniffi_relevancy_fn_method_relevancystore_user_interest_vector + 3, // relevancy:uniffi_relevancy_fn_method_relevancystore_user_interest_vector FfiConverterTypeRelevancyStore.lower(this), ) } @@ -416,7 +416,7 @@ export class FfiConverterTypeRelevancyStore extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'RelevancyStore' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRemoteSettings.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRemoteSettings.sys.mjs index 3dd4cb7ca6f1..0f12f8e783e7 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRemoteSettings.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRemoteSettings.sys.mjs @@ -356,7 +356,7 @@ export class RemoteSettings { throw e; } return UniFFIScaffolding.callSync( - 6, // remote_settings:uniffi_remote_settings_fn_constructor_remotesettings_new + 4, // remote_settings:uniffi_remote_settings_fn_constructor_remotesettings_new FfiConverterTypeRemoteSettingsConfig.lower(remoteSettingsConfig), ) } @@ -383,7 +383,7 @@ export class RemoteSettings { throw e; } return UniFFIScaffolding.callAsync( - 7, // remote_settings:uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path + 5, // remote_settings:uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path FfiConverterTypeRemoteSettings.lower(this), FfiConverterString.lower(attachmentId), FfiConverterString.lower(path), @@ -401,7 +401,7 @@ export class RemoteSettings { const liftError = (data) => FfiConverterTypeRemoteSettingsError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 8, // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records + 6, // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records FfiConverterTypeRemoteSettings.lower(this), ) } @@ -425,7 +425,7 @@ export class RemoteSettings { throw e; } return UniFFIScaffolding.callAsync( - 9, // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records_since + 7, // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records_since FfiConverterTypeRemoteSettings.lower(this), FfiConverterU64.lower(timestamp), ) @@ -452,7 +452,7 @@ export class FfiConverterTypeRemoteSettings extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'RemoteSettings' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs index 0d2c70cc84de..eb841e308748 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs @@ -484,7 +484,7 @@ export class SuggestStore { throw e; } return UniFFIScaffolding.callSync( - 11, // suggest:uniffi_suggest_fn_constructor_suggeststore_new + 8, // suggest:uniffi_suggest_fn_constructor_suggeststore_new FfiConverterString.lower(path), FfiConverterOptionalTypeRemoteSettingsConfig.lower(settingsConfig), ) @@ -496,7 +496,7 @@ export class SuggestStore { const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 12, // suggest:uniffi_suggest_fn_method_suggeststore_clear + 9, // suggest:uniffi_suggest_fn_method_suggeststore_clear FfiConverterTypeSuggestStore.lower(this), ) } @@ -507,53 +507,12 @@ export class SuggestStore { } } - clearDismissedSuggestions() { - const liftResult = (result) => undefined; - const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); - const functionCall = () => { - return UniFFIScaffolding.callAsync( - 13, // suggest:uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions - FfiConverterTypeSuggestStore.lower(this), - ) - } - try { - return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); - } catch (error) { - return Promise.reject(error) - } - } - - dismissSuggestion(rawSuggestionUrl) { - const liftResult = (result) => undefined; - const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); - const functionCall = () => { - try { - FfiConverterString.checkType(rawSuggestionUrl) - } catch (e) { - if (e instanceof UniFFITypeError) { - e.addItemDescriptionPart("rawSuggestionUrl"); - } - throw e; - } - return UniFFIScaffolding.callAsync( - 14, // suggest:uniffi_suggest_fn_method_suggeststore_dismiss_suggestion - FfiConverterTypeSuggestStore.lower(this), - FfiConverterString.lower(rawSuggestionUrl), - ) - } - try { - return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); - } catch (error) { - return Promise.reject(error) - } - } - fetchGlobalConfig() { const liftResult = (result) => FfiConverterTypeSuggestGlobalConfig.lift(result); const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 15, // suggest:uniffi_suggest_fn_method_suggeststore_fetch_global_config + 10, // suggest:uniffi_suggest_fn_method_suggeststore_fetch_global_config FfiConverterTypeSuggestStore.lower(this), ) } @@ -577,7 +536,7 @@ export class SuggestStore { throw e; } return UniFFIScaffolding.callAsync( - 16, // suggest:uniffi_suggest_fn_method_suggeststore_fetch_provider_config + 11, // suggest:uniffi_suggest_fn_method_suggeststore_fetch_provider_config FfiConverterTypeSuggestStore.lower(this), FfiConverterTypeSuggestionProvider.lower(provider), ) @@ -602,7 +561,7 @@ export class SuggestStore { throw e; } return UniFFIScaffolding.callAsync( - 17, // suggest:uniffi_suggest_fn_method_suggeststore_ingest + 12, // suggest:uniffi_suggest_fn_method_suggeststore_ingest FfiConverterTypeSuggestStore.lower(this), FfiConverterTypeSuggestIngestionConstraints.lower(constraints), ) @@ -619,7 +578,7 @@ export class SuggestStore { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callSync( - 18, // suggest:uniffi_suggest_fn_method_suggeststore_interrupt + 13, // suggest:uniffi_suggest_fn_method_suggeststore_interrupt FfiConverterTypeSuggestStore.lower(this), ) } @@ -639,7 +598,7 @@ export class SuggestStore { throw e; } return UniFFIScaffolding.callAsync( - 19, // suggest:uniffi_suggest_fn_method_suggeststore_query + 14, // suggest:uniffi_suggest_fn_method_suggeststore_query FfiConverterTypeSuggestStore.lower(this), FfiConverterTypeSuggestionQuery.lower(query), ) @@ -666,7 +625,7 @@ export class FfiConverterTypeSuggestStore extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'SuggestStore' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { @@ -706,7 +665,7 @@ export class SuggestStoreBuilder { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 21, // suggest:uniffi_suggest_fn_constructor_suggeststorebuilder_new + 15, // suggest:uniffi_suggest_fn_constructor_suggeststorebuilder_new ) } try { @@ -720,7 +679,7 @@ export class SuggestStoreBuilder { const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 22, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_build + 16, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_build FfiConverterTypeSuggestStoreBuilder.lower(this), ) } @@ -744,7 +703,7 @@ export class SuggestStoreBuilder { throw e; } return UniFFIScaffolding.callAsync( - 23, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_cache_path + 17, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_cache_path FfiConverterTypeSuggestStoreBuilder.lower(this), FfiConverterString.lower(path), ) @@ -769,7 +728,7 @@ export class SuggestStoreBuilder { throw e; } return UniFFIScaffolding.callAsync( - 24, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_data_path + 18, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_data_path FfiConverterTypeSuggestStoreBuilder.lower(this), FfiConverterString.lower(path), ) @@ -794,7 +753,7 @@ export class SuggestStoreBuilder { throw e; } return UniFFIScaffolding.callAsync( - 25, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config + 19, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config FfiConverterTypeSuggestStoreBuilder.lower(this), FfiConverterTypeRemoteSettingsConfig.lower(config), ) @@ -821,7 +780,7 @@ export class FfiConverterTypeSuggestStoreBuilder extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'SuggestStoreBuilder' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { @@ -2104,7 +2063,7 @@ export function rawSuggestionUrlMatches(rawUrl,url) { throw e; } return UniFFIScaffolding.callSync( - 26, // suggest:uniffi_suggest_fn_func_raw_suggestion_url_matches + 20, // suggest:uniffi_suggest_fn_func_raw_suggestion_url_matches FfiConverterString.lower(rawUrl), FfiConverterString.lower(url), ) diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs index bde8f9aed2f9..be4d346733c3 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs @@ -361,7 +361,7 @@ export class TabsBridgedEngine { const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 28, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_apply + 21, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_apply FfiConverterTypeTabsBridgedEngine.lower(this), ) } @@ -385,7 +385,7 @@ export class TabsBridgedEngine { throw e; } return UniFFIScaffolding.callAsync( - 29, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id + 22, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id FfiConverterTypeTabsBridgedEngine.lower(this), FfiConverterString.lower(newSyncId), ) @@ -402,7 +402,7 @@ export class TabsBridgedEngine { const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 30, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_last_sync + 23, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_last_sync FfiConverterTypeTabsBridgedEngine.lower(this), ) } @@ -426,7 +426,7 @@ export class TabsBridgedEngine { throw e; } return UniFFIScaffolding.callAsync( - 31, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync + 24, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync FfiConverterTypeTabsBridgedEngine.lower(this), FfiConverterString.lower(clientData), ) @@ -443,7 +443,7 @@ export class TabsBridgedEngine { const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 32, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset + 25, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset FfiConverterTypeTabsBridgedEngine.lower(this), ) } @@ -459,7 +459,7 @@ export class TabsBridgedEngine { const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 33, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id + 26, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id FfiConverterTypeTabsBridgedEngine.lower(this), ) } @@ -483,7 +483,7 @@ export class TabsBridgedEngine { throw e; } return UniFFIScaffolding.callAsync( - 34, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync + 27, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync FfiConverterTypeTabsBridgedEngine.lower(this), FfiConverterI64.lower(lastSync), ) @@ -516,7 +516,7 @@ export class TabsBridgedEngine { throw e; } return UniFFIScaffolding.callAsync( - 35, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded + 28, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded FfiConverterTypeTabsBridgedEngine.lower(this), FfiConverterI64.lower(newTimestamp), FfiConverterSequenceTypeTabsGuid.lower(uploadedIds), @@ -542,7 +542,7 @@ export class TabsBridgedEngine { throw e; } return UniFFIScaffolding.callAsync( - 36, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_store_incoming + 29, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_store_incoming FfiConverterTypeTabsBridgedEngine.lower(this), FfiConverterSequencestring.lower(incomingEnvelopesAsJson), ) @@ -559,7 +559,7 @@ export class TabsBridgedEngine { const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 37, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_finished + 30, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_finished FfiConverterTypeTabsBridgedEngine.lower(this), ) } @@ -575,7 +575,7 @@ export class TabsBridgedEngine { const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 38, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_id + 31, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_id FfiConverterTypeTabsBridgedEngine.lower(this), ) } @@ -591,7 +591,7 @@ export class TabsBridgedEngine { const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 39, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_started + 32, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_started FfiConverterTypeTabsBridgedEngine.lower(this), ) } @@ -607,7 +607,7 @@ export class TabsBridgedEngine { const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 40, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_wipe + 33, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_wipe FfiConverterTypeTabsBridgedEngine.lower(this), ) } @@ -633,7 +633,7 @@ export class FfiConverterTypeTabsBridgedEngine extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'TabsBridgedEngine' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { @@ -681,7 +681,7 @@ export class TabsStore { throw e; } return UniFFIScaffolding.callAsync( - 42, // tabs:uniffi_tabs_fn_constructor_tabsstore_new + 34, // tabs:uniffi_tabs_fn_constructor_tabsstore_new FfiConverterString.lower(path), ) } @@ -696,7 +696,7 @@ export class TabsStore { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 43, // tabs:uniffi_tabs_fn_method_tabsstore_bridged_engine + 35, // tabs:uniffi_tabs_fn_method_tabsstore_bridged_engine FfiConverterTypeTabsStore.lower(this), ) } @@ -712,7 +712,7 @@ export class TabsStore { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 44, // tabs:uniffi_tabs_fn_method_tabsstore_get_all + 36, // tabs:uniffi_tabs_fn_method_tabsstore_get_all FfiConverterTypeTabsStore.lower(this), ) } @@ -728,7 +728,7 @@ export class TabsStore { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 45, // tabs:uniffi_tabs_fn_method_tabsstore_register_with_sync_manager + 37, // tabs:uniffi_tabs_fn_method_tabsstore_register_with_sync_manager FfiConverterTypeTabsStore.lower(this), ) } @@ -752,7 +752,7 @@ export class TabsStore { throw e; } return UniFFIScaffolding.callAsync( - 46, // tabs:uniffi_tabs_fn_method_tabsstore_set_local_tabs + 38, // tabs:uniffi_tabs_fn_method_tabsstore_set_local_tabs FfiConverterTypeTabsStore.lower(this), FfiConverterSequenceTypeRemoteTabRecord.lower(remoteTabs), ) @@ -779,7 +779,7 @@ export class FfiConverterTypeTabsStore extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'TabsStore' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/config.toml b/toolkit/components/uniffi-bindgen-gecko-js/config.toml index 9add08001ce3..7b7943dfbdcf 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/config.toml +++ b/toolkit/components/uniffi-bindgen-gecko-js/config.toml @@ -72,19 +72,16 @@ crate_name = "uniffi_todolist" udl_file = "third_party/rust/uniffi-example-todolist/src/todolist.udl" fixture = true -# Temporarily disabled until we can re-enable callback support -# -# I think this can be done when we implement https://bugzilla.mozilla.org/show_bug.cgi?id=1888668 -# [fixture_callbacks] -# crate_name = "uniffi_fixture_callbacks" -# udl_file = "toolkit/components/uniffi-fixture-callbacks/src/callbacks.udl" -# fixture = true -# -# [fixture_callbacks.receiver_thread] -# default = "worker" -# main = [ -# "log_even_numbers_main_thread", -# ] +[fixture_callbacks] +crate_name = "uniffi_fixture_callbacks" +udl_file = "toolkit/components/uniffi-fixture-callbacks/src/callbacks.udl" +fixture = true + +[fixture_callbacks.receiver_thread] +default = "worker" +main = [ + "log_even_numbers_main_thread", +] [custom_types] crate_name = "uniffi_custom_types" diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustArithmetic.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustArithmetic.sys.mjs index 62766a45a4ae..e60f95decea1 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustArithmetic.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustArithmetic.sys.mjs @@ -377,7 +377,7 @@ export function add(a,b) { throw e; } return UniFFIScaffolding.callAsync( - 47, // arithmetic:uniffi_arithmetical_fn_func_add + 39, // arithmetic:uniffi_arithmetical_fn_func_add FfiConverterU64.lower(a), FfiConverterU64.lower(b), ) @@ -411,7 +411,7 @@ export function div(dividend,divisor) { throw e; } return UniFFIScaffolding.callAsync( - 48, // arithmetic:uniffi_arithmetical_fn_func_div + 40, // arithmetic:uniffi_arithmetical_fn_func_div FfiConverterU64.lower(dividend), FfiConverterU64.lower(divisor), ) @@ -445,7 +445,7 @@ export function equal(a,b) { throw e; } return UniFFIScaffolding.callAsync( - 49, // arithmetic:uniffi_arithmetical_fn_func_equal + 41, // arithmetic:uniffi_arithmetical_fn_func_equal FfiConverterU64.lower(a), FfiConverterU64.lower(b), ) @@ -479,7 +479,7 @@ export function sub(a,b) { throw e; } return UniFFIScaffolding.callAsync( - 50, // arithmetic:uniffi_arithmetical_fn_func_sub + 42, // arithmetic:uniffi_arithmetical_fn_func_sub FfiConverterU64.lower(a), FfiConverterU64.lower(b), ) diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustCustomTypes.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustCustomTypes.sys.mjs index 581478cc8a31..107da01016c7 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustCustomTypes.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustCustomTypes.sys.mjs @@ -455,7 +455,7 @@ export function getCustomTypesDemo(demo) { throw e; } return UniFFIScaffolding.callAsync( - 51, // custom_types:uniffi_uniffi_custom_types_fn_func_get_custom_types_demo + 43, // custom_types:uniffi_uniffi_custom_types_fn_func_get_custom_types_demo FfiConverterOptionalTypeCustomTypesDemo.lower(demo), ) } diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustExternalTypes.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustExternalTypes.sys.mjs index 88c939022532..6c6f9f9bb703 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustExternalTypes.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustExternalTypes.sys.mjs @@ -381,7 +381,7 @@ export function gradient(value) { throw e; } return UniFFIScaffolding.callAsync( - 52, // external_types:uniffi_uniffi_fixture_external_types_fn_func_gradient + 44, // external_types:uniffi_uniffi_fixture_external_types_fn_func_gradient FfiConverterOptionalTypeLine.lower(value), ) } @@ -414,7 +414,7 @@ export function intersection(ln1,ln2) { throw e; } return UniFFIScaffolding.callAsync( - 53, // external_types:uniffi_uniffi_fixture_external_types_fn_func_intersection + 45, // external_types:uniffi_uniffi_fixture_external_types_fn_func_intersection FfiConverterTypeLine.lower(ln1), FfiConverterTypeLine.lower(ln2), ) diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustGeometry.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustGeometry.sys.mjs index 22b35a18279a..830775dbf982 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustGeometry.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustGeometry.sys.mjs @@ -474,7 +474,7 @@ export function gradient(ln) { throw e; } return UniFFIScaffolding.callAsync( - 54, // geometry:uniffi_uniffi_geometry_fn_func_gradient + 48, // geometry:uniffi_uniffi_geometry_fn_func_gradient FfiConverterTypeLine.lower(ln), ) } @@ -507,7 +507,7 @@ export function intersection(ln1,ln2) { throw e; } return UniFFIScaffolding.callAsync( - 55, // geometry:uniffi_uniffi_geometry_fn_func_intersection + 49, // geometry:uniffi_uniffi_geometry_fn_func_intersection FfiConverterTypeLine.lower(ln1), FfiConverterTypeLine.lower(ln2), ) diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRondpoint.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRondpoint.sys.mjs index bab2f99daa00..2d55aa787217 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRondpoint.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRondpoint.sys.mjs @@ -620,7 +620,7 @@ export class Optionneur { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 57, // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_optionneur_new + 50, // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_optionneur_new ) } try { @@ -642,7 +642,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 58, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean + 51, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean FfiConverterTypeOptionneur.lower(this), FfiConverterBool.lower(value), ) @@ -667,7 +667,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 59, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum + 52, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum FfiConverterTypeOptionneur.lower(this), FfiConverterTypeEnumeration.lower(value), ) @@ -692,7 +692,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 60, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32 + 53, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32 FfiConverterTypeOptionneur.lower(this), FfiConverterF32.lower(value), ) @@ -717,7 +717,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 61, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64 + 54, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64 FfiConverterTypeOptionneur.lower(this), FfiConverterF64.lower(value), ) @@ -742,7 +742,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 62, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec + 55, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec FfiConverterTypeOptionneur.lower(this), FfiConverterI16.lower(value), ) @@ -767,7 +767,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 63, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex + 56, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex FfiConverterTypeOptionneur.lower(this), FfiConverterI16.lower(value), ) @@ -792,7 +792,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 64, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec + 57, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec FfiConverterTypeOptionneur.lower(this), FfiConverterI32.lower(value), ) @@ -817,7 +817,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 65, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex + 58, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex FfiConverterTypeOptionneur.lower(this), FfiConverterI32.lower(value), ) @@ -842,7 +842,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 66, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec + 59, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec FfiConverterTypeOptionneur.lower(this), FfiConverterI64.lower(value), ) @@ -867,7 +867,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 67, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex + 60, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex FfiConverterTypeOptionneur.lower(this), FfiConverterI64.lower(value), ) @@ -892,7 +892,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 68, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec + 61, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec FfiConverterTypeOptionneur.lower(this), FfiConverterI8.lower(value), ) @@ -917,7 +917,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 69, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex + 62, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex FfiConverterTypeOptionneur.lower(this), FfiConverterI8.lower(value), ) @@ -942,7 +942,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 70, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null + 63, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null FfiConverterTypeOptionneur.lower(this), FfiConverterOptionalstring.lower(value), ) @@ -967,7 +967,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 71, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence + 64, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence FfiConverterTypeOptionneur.lower(this), FfiConverterSequencestring.lower(value), ) @@ -992,7 +992,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 72, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string + 65, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string FfiConverterTypeOptionneur.lower(this), FfiConverterString.lower(value), ) @@ -1017,7 +1017,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 73, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec + 66, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec FfiConverterTypeOptionneur.lower(this), FfiConverterU16.lower(value), ) @@ -1042,7 +1042,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 74, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex + 67, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex FfiConverterTypeOptionneur.lower(this), FfiConverterU16.lower(value), ) @@ -1067,7 +1067,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 75, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec + 68, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec FfiConverterTypeOptionneur.lower(this), FfiConverterU32.lower(value), ) @@ -1092,7 +1092,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 76, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex + 69, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex FfiConverterTypeOptionneur.lower(this), FfiConverterU32.lower(value), ) @@ -1117,7 +1117,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 77, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct + 70, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct FfiConverterTypeOptionneur.lower(this), FfiConverterU32.lower(value), ) @@ -1142,7 +1142,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 78, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec + 71, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec FfiConverterTypeOptionneur.lower(this), FfiConverterU64.lower(value), ) @@ -1167,7 +1167,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 79, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex + 72, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex FfiConverterTypeOptionneur.lower(this), FfiConverterU64.lower(value), ) @@ -1192,7 +1192,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 80, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec + 73, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec FfiConverterTypeOptionneur.lower(this), FfiConverterU8.lower(value), ) @@ -1217,7 +1217,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 81, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex + 74, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex FfiConverterTypeOptionneur.lower(this), FfiConverterU8.lower(value), ) @@ -1242,7 +1242,7 @@ export class Optionneur { throw e; } return UniFFIScaffolding.callAsync( - 82, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero + 75, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero FfiConverterTypeOptionneur.lower(this), FfiConverterOptionali32.lower(value), ) @@ -1269,7 +1269,7 @@ export class FfiConverterTypeOptionneur extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'Optionneur' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { @@ -1309,7 +1309,7 @@ export class Retourneur { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 84, // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_retourneur_new + 76, // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_retourneur_new ) } try { @@ -1331,7 +1331,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 85, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean + 77, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean FfiConverterTypeRetourneur.lower(this), FfiConverterBool.lower(value), ) @@ -1356,7 +1356,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 86, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double + 78, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double FfiConverterTypeRetourneur.lower(this), FfiConverterF64.lower(value), ) @@ -1381,7 +1381,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 87, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float + 79, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float FfiConverterTypeRetourneur.lower(this), FfiConverterF32.lower(value), ) @@ -1406,7 +1406,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 88, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16 + 80, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16 FfiConverterTypeRetourneur.lower(this), FfiConverterI16.lower(value), ) @@ -1431,7 +1431,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 89, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32 + 81, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32 FfiConverterTypeRetourneur.lower(this), FfiConverterI32.lower(value), ) @@ -1456,7 +1456,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 90, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64 + 82, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64 FfiConverterTypeRetourneur.lower(this), FfiConverterI64.lower(value), ) @@ -1481,7 +1481,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 91, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8 + 83, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8 FfiConverterTypeRetourneur.lower(this), FfiConverterI8.lower(value), ) @@ -1506,7 +1506,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 92, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres + 84, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres FfiConverterTypeRetourneur.lower(this), FfiConverterTypeDictionnaireNombres.lower(value), ) @@ -1531,7 +1531,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 93, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes + 85, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes FfiConverterTypeRetourneur.lower(this), FfiConverterTypeDictionnaireNombresSignes.lower(value), ) @@ -1556,7 +1556,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 94, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire + 86, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire FfiConverterTypeRetourneur.lower(this), FfiConverterTypeOptionneurDictionnaire.lower(value), ) @@ -1581,7 +1581,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 95, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string + 87, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string FfiConverterTypeRetourneur.lower(this), FfiConverterString.lower(value), ) @@ -1606,7 +1606,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 96, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16 + 88, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16 FfiConverterTypeRetourneur.lower(this), FfiConverterU16.lower(value), ) @@ -1631,7 +1631,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 97, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32 + 89, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32 FfiConverterTypeRetourneur.lower(this), FfiConverterU32.lower(value), ) @@ -1656,7 +1656,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 98, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64 + 90, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64 FfiConverterTypeRetourneur.lower(this), FfiConverterU64.lower(value), ) @@ -1681,7 +1681,7 @@ export class Retourneur { throw e; } return UniFFIScaffolding.callAsync( - 99, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8 + 91, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8 FfiConverterTypeRetourneur.lower(this), FfiConverterU8.lower(value), ) @@ -1708,7 +1708,7 @@ export class FfiConverterTypeRetourneur extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'Retourneur' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { @@ -1748,7 +1748,7 @@ export class Stringifier { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 101, // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_stringifier_new + 92, // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_stringifier_new ) } try { @@ -1770,7 +1770,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 102, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean + 93, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean FfiConverterTypeStringifier.lower(this), FfiConverterBool.lower(value), ) @@ -1795,7 +1795,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 103, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double + 94, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double FfiConverterTypeStringifier.lower(this), FfiConverterF64.lower(value), ) @@ -1820,7 +1820,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 104, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float + 95, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float FfiConverterTypeStringifier.lower(this), FfiConverterF32.lower(value), ) @@ -1845,7 +1845,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 105, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16 + 96, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16 FfiConverterTypeStringifier.lower(this), FfiConverterI16.lower(value), ) @@ -1870,7 +1870,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 106, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32 + 97, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32 FfiConverterTypeStringifier.lower(this), FfiConverterI32.lower(value), ) @@ -1895,7 +1895,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 107, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64 + 98, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64 FfiConverterTypeStringifier.lower(this), FfiConverterI64.lower(value), ) @@ -1920,7 +1920,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 108, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8 + 99, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8 FfiConverterTypeStringifier.lower(this), FfiConverterI8.lower(value), ) @@ -1945,7 +1945,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 109, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16 + 100, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16 FfiConverterTypeStringifier.lower(this), FfiConverterU16.lower(value), ) @@ -1970,7 +1970,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 110, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32 + 101, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32 FfiConverterTypeStringifier.lower(this), FfiConverterU32.lower(value), ) @@ -1995,7 +1995,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 111, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64 + 102, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64 FfiConverterTypeStringifier.lower(this), FfiConverterU64.lower(value), ) @@ -2020,7 +2020,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 112, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8 + 103, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8 FfiConverterTypeStringifier.lower(this), FfiConverterU8.lower(value), ) @@ -2045,7 +2045,7 @@ export class Stringifier { throw e; } return UniFFIScaffolding.callAsync( - 113, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string + 104, // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string FfiConverterTypeStringifier.lower(this), FfiConverterString.lower(value), ) @@ -2072,7 +2072,7 @@ export class FfiConverterTypeStringifier extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'Stringifier' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { @@ -3284,7 +3284,7 @@ export function copieCarte(c) { throw e; } return UniFFIScaffolding.callAsync( - 114, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_carte + 105, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_carte FfiConverterMapStringTypeEnumerationAvecDonnees.lower(c), ) } @@ -3309,7 +3309,7 @@ export function copieDictionnaire(d) { throw e; } return UniFFIScaffolding.callAsync( - 115, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire + 106, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire FfiConverterTypeDictionnaire.lower(d), ) } @@ -3334,7 +3334,7 @@ export function copieEnumeration(e) { throw e; } return UniFFIScaffolding.callAsync( - 116, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumeration + 107, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumeration FfiConverterTypeEnumeration.lower(e), ) } @@ -3359,7 +3359,7 @@ export function copieEnumerations(e) { throw e; } return UniFFIScaffolding.callAsync( - 117, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumerations + 108, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumerations FfiConverterSequenceTypeEnumeration.lower(e), ) } @@ -3384,7 +3384,7 @@ export function switcheroo(b) { throw e; } return UniFFIScaffolding.callAsync( - 118, // rondpoint:uniffi_uniffi_rondpoint_fn_func_switcheroo + 109, // rondpoint:uniffi_uniffi_rondpoint_fn_func_switcheroo FfiConverterBool.lower(b), ) } diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustSprites.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustSprites.sys.mjs index 3831e3341e23..2a045bdbcad1 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustSprites.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustSprites.sys.mjs @@ -325,7 +325,7 @@ export class Sprite { throw e; } return UniFFIScaffolding.callAsync( - 120, // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new + 110, // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new FfiConverterOptionalTypePoint.lower(initialPosition), ) } @@ -361,7 +361,7 @@ export class Sprite { throw e; } return UniFFIScaffolding.callAsync( - 121, // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to + 111, // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to FfiConverterTypePoint.lower(reference), FfiConverterTypeVector.lower(direction), ) @@ -377,7 +377,7 @@ export class Sprite { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 122, // sprites:uniffi_uniffi_sprites_fn_method_sprite_get_position + 112, // sprites:uniffi_uniffi_sprites_fn_method_sprite_get_position FfiConverterTypeSprite.lower(this), ) } @@ -401,7 +401,7 @@ export class Sprite { throw e; } return UniFFIScaffolding.callAsync( - 123, // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_by + 113, // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_by FfiConverterTypeSprite.lower(this), FfiConverterTypeVector.lower(direction), ) @@ -426,7 +426,7 @@ export class Sprite { throw e; } return UniFFIScaffolding.callAsync( - 124, // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_to + 114, // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_to FfiConverterTypeSprite.lower(this), FfiConverterTypePoint.lower(position), ) @@ -453,7 +453,7 @@ export class FfiConverterTypeSprite extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'Sprite' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { @@ -678,7 +678,7 @@ export function translate(position,direction) { throw e; } return UniFFIScaffolding.callAsync( - 125, // sprites:uniffi_uniffi_sprites_fn_func_translate + 115, // sprites:uniffi_uniffi_sprites_fn_func_translate FfiConverterTypePoint.lower(position), FfiConverterTypeVector.lower(direction), ) diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustTodolist.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustTodolist.sys.mjs index a4b53dcd1571..9c6f36019454 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustTodolist.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustTodolist.sys.mjs @@ -298,7 +298,7 @@ export class TodoList { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 127, // todolist:uniffi_uniffi_todolist_fn_constructor_todolist_new + 116, // todolist:uniffi_uniffi_todolist_fn_constructor_todolist_new ) } try { @@ -320,7 +320,7 @@ export class TodoList { throw e; } return UniFFIScaffolding.callAsync( - 128, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entries + 117, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entries FfiConverterTypeTodoList.lower(this), FfiConverterSequenceTypeTodoEntry.lower(entries), ) @@ -345,7 +345,7 @@ export class TodoList { throw e; } return UniFFIScaffolding.callAsync( - 129, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entry + 118, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entry FfiConverterTypeTodoList.lower(this), FfiConverterTypeTodoEntry.lower(entry), ) @@ -370,7 +370,7 @@ export class TodoList { throw e; } return UniFFIScaffolding.callAsync( - 130, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_item + 119, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_item FfiConverterTypeTodoList.lower(this), FfiConverterString.lower(todo), ) @@ -395,7 +395,7 @@ export class TodoList { throw e; } return UniFFIScaffolding.callAsync( - 131, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_items + 120, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_items FfiConverterTypeTodoList.lower(this), FfiConverterSequencestring.lower(items), ) @@ -420,7 +420,7 @@ export class TodoList { throw e; } return UniFFIScaffolding.callAsync( - 132, // todolist:uniffi_uniffi_todolist_fn_method_todolist_clear_item + 121, // todolist:uniffi_uniffi_todolist_fn_method_todolist_clear_item FfiConverterTypeTodoList.lower(this), FfiConverterString.lower(todo), ) @@ -437,7 +437,7 @@ export class TodoList { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 133, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_entries + 122, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_entries FfiConverterTypeTodoList.lower(this), ) } @@ -453,7 +453,7 @@ export class TodoList { const liftError = (data) => FfiConverterTypeTodoError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 134, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_first + 123, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_first FfiConverterTypeTodoList.lower(this), ) } @@ -469,7 +469,7 @@ export class TodoList { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 135, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_items + 124, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_items FfiConverterTypeTodoList.lower(this), ) } @@ -485,7 +485,7 @@ export class TodoList { const liftError = (data) => FfiConverterTypeTodoError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 136, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last + 125, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last FfiConverterTypeTodoList.lower(this), ) } @@ -501,7 +501,7 @@ export class TodoList { const liftError = (data) => FfiConverterTypeTodoError.lift(data); const functionCall = () => { return UniFFIScaffolding.callAsync( - 137, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last_entry + 126, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last_entry FfiConverterTypeTodoList.lower(this), ) } @@ -517,7 +517,7 @@ export class TodoList { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 138, // todolist:uniffi_uniffi_todolist_fn_method_todolist_make_default + 127, // todolist:uniffi_uniffi_todolist_fn_method_todolist_make_default FfiConverterTypeTodoList.lower(this), ) } @@ -543,7 +543,7 @@ export class FfiConverterTypeTodoList extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a 'TodoList' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { @@ -880,7 +880,7 @@ export function createEntryWith(todo) { throw e; } return UniFFIScaffolding.callAsync( - 139, // todolist:uniffi_uniffi_todolist_fn_func_create_entry_with + 128, // todolist:uniffi_uniffi_todolist_fn_func_create_entry_with FfiConverterString.lower(todo), ) } @@ -897,7 +897,7 @@ export function getDefaultList() { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 140, // todolist:uniffi_uniffi_todolist_fn_func_get_default_list + 129, // todolist:uniffi_uniffi_todolist_fn_func_get_default_list ) } try { @@ -921,7 +921,7 @@ export function setDefaultList(list) { throw e; } return UniFFIScaffolding.callAsync( - 141, // todolist:uniffi_uniffi_todolist_fn_func_set_default_list + 130, // todolist:uniffi_uniffi_todolist_fn_func_set_default_list FfiConverterTypeTodoList.lower(list), ) } diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml index 67baf992e2de..76814ff1991d 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml @@ -2,10 +2,7 @@ ["test_arithmetic.js"] -# Temporarily disabled until we can re-enable callback support -# -# I think this can be done when we implement https://bugzilla.mozilla.org/show_bug.cgi?id=1888668 -# ["test_callbacks.js"] +["test_callbacks.js"] ["test_custom_types.js"] diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs index 7b63e8f3af7a..685c3c2bf370 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs @@ -136,25 +136,31 @@ pub impl FfiType { // Type for the Rust scaffolding code fn rust_type(&self) -> String { match self { - FfiType::UInt8 => "uint8_t".to_owned(), - FfiType::Int8 => "int8_t".to_owned(), - FfiType::UInt16 => "uint16_t".to_owned(), - FfiType::Int16 => "int16_t".to_owned(), - FfiType::UInt32 => "uint32_t".to_owned(), - FfiType::Int32 => "int32_t".to_owned(), - FfiType::UInt64 => "uint64_t".to_owned(), - FfiType::Int64 => "int64_t".to_owned(), - FfiType::Float32 => "float".to_owned(), - FfiType::Float64 => "double".to_owned(), - FfiType::RustBuffer(_) => "RustBuffer".to_owned(), - FfiType::RustArcPtr(_) => "void *".to_owned(), + FfiType::UInt8 => "uint8_t", + FfiType::Int8 => "int8_t", + FfiType::UInt16 => "uint16_t", + FfiType::Int16 => "int16_t", + FfiType::UInt32 => "uint32_t", + FfiType::Int32 => "int32_t", + FfiType::UInt64 => "uint64_t", + FfiType::Int64 => "int64_t", + FfiType::Float32 => "float", + FfiType::Float64 => "double", + FfiType::RustBuffer(_) => "RustBuffer", + FfiType::RustArcPtr(_) => "void *", + FfiType::ForeignCallback => "ForeignCallback", FfiType::ForeignBytes => unimplemented!("ForeignBytes not supported"), - FfiType::Handle => "uint64_t".to_owned(), - FfiType::RustCallStatus => "RustCallStatus".to_owned(), - FfiType::Callback(name) | FfiType::Struct(name) => name.to_owned(), - FfiType::VoidPointer => "void *".to_owned(), - FfiType::Reference(_) => unimplemented!("References not supported"), + FfiType::ForeignExecutorHandle => unimplemented!("ForeignExecutorHandle not supported"), + FfiType::ForeignExecutorCallback => { + unimplemented!("ForeignExecutorCallback not supported") + } + FfiType::RustFutureHandle + | FfiType::RustFutureContinuationCallback + | FfiType::RustFutureContinuationData => { + unimplemented!("Rust async functions not supported") + } } + .to_owned() } } diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs index cd9af529a7c4..efd7b4245628 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs @@ -92,8 +92,7 @@ pub impl Literal { Literal::Enum(name, typ) => render_enum_literal(typ, name), Literal::EmptyMap => "{}".to_string(), Literal::EmptySequence => "[]".to_string(), - Literal::Some { inner } => inner.render(), - Literal::None => "null".to_string(), + Literal::Null => "null".to_string(), } } } @@ -259,6 +258,7 @@ pub impl Type { | Type::CallbackInterface { name, .. } => format!("Type{name}"), Type::Timestamp => "Timestamp".into(), Type::Duration => "Duration".into(), + Type::ForeignExecutor => "ForeignExecutor".into(), Type::Optional { inner_type } => format!("Optional{}", inner_type.canonical_name()), Type::Sequence { inner_type } => format!("Sequence{}", inner_type.canonical_name()), Type::Map { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp index 83aeae808650..5c4ed8c2f56f 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp @@ -37,8 +37,7 @@ extern "C" { {%- let pointer_type = ci.pointer_type(object) %} const static mozilla::uniffi::UniFFIPointerType {{ pointer_type }} { "{{ "{}::{}"|format(ci.namespace(), object.name()) }}"_ns, - {{ object.ffi_object_clone().rust_name() }}, - {{ object.ffi_object_free().rust_name() }}, + {{ object.ffi_object_free().rust_name() }} }; {%- endfor %} {%- endfor %} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.sys.mjs index 594c00d92be7..204bf752ddca 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.sys.mjs +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.sys.mjs @@ -55,7 +55,7 @@ export class {{ ffi_converter }} extends FfiConverter { if (!(ptr instanceof UniFFIPointer)) { throw new UniFFITypeError("Object is not a '{{ object.nm() }}' instance"); } - return ptr.clone(); + return ptr; } static read(dataStream) { diff --git a/toolkit/components/uniffi-fixture-external-types/Cargo.toml b/toolkit/components/uniffi-fixture-external-types/Cargo.toml index 46ee01662d22..f9ac840c3fa3 100644 --- a/toolkit/components/uniffi-fixture-external-types/Cargo.toml +++ b/toolkit/components/uniffi-fixture-external-types/Cargo.toml @@ -7,7 +7,7 @@ license = "MPL-2.0" publish = false [dependencies] -uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de" } +uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b" } uniffi = { workspace = true } thiserror = "1.0" diff --git a/toolkit/components/uniffi-js/OwnedRustBuffer.cpp b/toolkit/components/uniffi-js/OwnedRustBuffer.cpp index f14033a21392..4e334a966e75 100644 --- a/toolkit/components/uniffi-js/OwnedRustBuffer.cpp +++ b/toolkit/components/uniffi-js/OwnedRustBuffer.cpp @@ -27,7 +27,7 @@ Result OwnedRustBuffer::FromArrayBuffer( RustCallStatus status{}; RustBuffer buf = uniffi_rustbuffer_alloc( - static_cast(aData.Length()), &status); + static_cast(aData.Length()), &status); buf.len = aData.Length(); if (status.code != 0) { if (status.error_buf.data) { @@ -84,7 +84,7 @@ RustBuffer OwnedRustBuffer::IntoRustBuffer() { JSObject* OwnedRustBuffer::IntoArrayBuffer(JSContext* cx) { JS::Rooted obj(cx); { - auto len = mBuf.len; + int32_t len = mBuf.len; void* data = mBuf.data; auto userData = MakeUnique(std::move(*this)); UniquePtr dataPtr{ diff --git a/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp b/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp index fe85fdbbd6ad..739569db01c1 100644 --- a/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp +++ b/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp @@ -31,9 +31,11 @@ extern "C" { RustBuffer uniffi_uniffi_custom_types_fn_func_get_custom_types_demo(RustBuffer, RustCallStatus*); double uniffi_uniffi_fixture_external_types_fn_func_gradient(RustBuffer, RustCallStatus*); RustBuffer uniffi_uniffi_fixture_external_types_fn_func_intersection(RustBuffer, RustBuffer, RustCallStatus*); + void uniffi_uniffi_fixture_callbacks_fn_init_callback_logger(ForeignCallback, RustCallStatus*); + void uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers(uint64_t, RustBuffer, RustCallStatus*); + void uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers_main_thread(uint64_t, RustBuffer, RustCallStatus*); double uniffi_uniffi_geometry_fn_func_gradient(RustBuffer, RustCallStatus*); RustBuffer uniffi_uniffi_geometry_fn_func_intersection(RustBuffer, RustBuffer, RustCallStatus*); - void * uniffi_uniffi_rondpoint_fn_clone_optionneur(void *, RustCallStatus*); void uniffi_uniffi_rondpoint_fn_free_optionneur(void *, RustCallStatus*); void * uniffi_uniffi_rondpoint_fn_constructor_optionneur_new(RustCallStatus*); int8_t uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean(void *, int8_t, RustCallStatus*); @@ -61,7 +63,6 @@ extern "C" { uint8_t uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec(void *, uint8_t, RustCallStatus*); uint8_t uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex(void *, uint8_t, RustCallStatus*); RustBuffer uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero(void *, RustBuffer, RustCallStatus*); - void * uniffi_uniffi_rondpoint_fn_clone_retourneur(void *, RustCallStatus*); void uniffi_uniffi_rondpoint_fn_free_retourneur(void *, RustCallStatus*); void * uniffi_uniffi_rondpoint_fn_constructor_retourneur_new(RustCallStatus*); int8_t uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean(void *, int8_t, RustCallStatus*); @@ -79,7 +80,6 @@ extern "C" { uint32_t uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32(void *, uint32_t, RustCallStatus*); uint64_t uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64(void *, uint64_t, RustCallStatus*); uint8_t uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8(void *, uint8_t, RustCallStatus*); - void * uniffi_uniffi_rondpoint_fn_clone_stringifier(void *, RustCallStatus*); void uniffi_uniffi_rondpoint_fn_free_stringifier(void *, RustCallStatus*); void * uniffi_uniffi_rondpoint_fn_constructor_stringifier_new(RustCallStatus*); RustBuffer uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean(void *, int8_t, RustCallStatus*); @@ -99,7 +99,6 @@ extern "C" { RustBuffer uniffi_uniffi_rondpoint_fn_func_copie_enumeration(RustBuffer, RustCallStatus*); RustBuffer uniffi_uniffi_rondpoint_fn_func_copie_enumerations(RustBuffer, RustCallStatus*); int8_t uniffi_uniffi_rondpoint_fn_func_switcheroo(int8_t, RustCallStatus*); - void * uniffi_uniffi_sprites_fn_clone_sprite(void *, RustCallStatus*); void uniffi_uniffi_sprites_fn_free_sprite(void *, RustCallStatus*); void * uniffi_uniffi_sprites_fn_constructor_sprite_new(RustBuffer, RustCallStatus*); void * uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to(RustBuffer, RustBuffer, RustCallStatus*); @@ -107,7 +106,6 @@ extern "C" { void uniffi_uniffi_sprites_fn_method_sprite_move_by(void *, RustBuffer, RustCallStatus*); void uniffi_uniffi_sprites_fn_method_sprite_move_to(void *, RustBuffer, RustCallStatus*); RustBuffer uniffi_uniffi_sprites_fn_func_translate(RustBuffer, RustBuffer, RustCallStatus*); - void * uniffi_uniffi_todolist_fn_clone_todolist(void *, RustCallStatus*); void uniffi_uniffi_todolist_fn_free_todolist(void *, RustCallStatus*); void * uniffi_uniffi_todolist_fn_constructor_todolist_new(RustCallStatus*); void uniffi_uniffi_todolist_fn_method_todolist_add_entries(void *, RustBuffer, RustCallStatus*); @@ -129,35 +127,49 @@ extern "C" { // Define pointer types const static mozilla::uniffi::UniFFIPointerType kRondpointOptionneurPointerType { "rondpoint::Optionneur"_ns, - uniffi_uniffi_rondpoint_fn_clone_optionneur, - uniffi_uniffi_rondpoint_fn_free_optionneur, + uniffi_uniffi_rondpoint_fn_free_optionneur }; const static mozilla::uniffi::UniFFIPointerType kRondpointRetourneurPointerType { "rondpoint::Retourneur"_ns, - uniffi_uniffi_rondpoint_fn_clone_retourneur, - uniffi_uniffi_rondpoint_fn_free_retourneur, + uniffi_uniffi_rondpoint_fn_free_retourneur }; const static mozilla::uniffi::UniFFIPointerType kRondpointStringifierPointerType { "rondpoint::Stringifier"_ns, - uniffi_uniffi_rondpoint_fn_clone_stringifier, - uniffi_uniffi_rondpoint_fn_free_stringifier, + uniffi_uniffi_rondpoint_fn_free_stringifier }; const static mozilla::uniffi::UniFFIPointerType kSpritesSpritePointerType { "sprites::Sprite"_ns, - uniffi_uniffi_sprites_fn_clone_sprite, - uniffi_uniffi_sprites_fn_free_sprite, + uniffi_uniffi_sprites_fn_free_sprite }; const static mozilla::uniffi::UniFFIPointerType kTodolistTodoListPointerType { "todolist::TodoList"_ns, - uniffi_uniffi_todolist_fn_clone_todolist, - uniffi_uniffi_todolist_fn_free_todolist, + uniffi_uniffi_todolist_fn_free_todolist }; // Define the data we need per-callback interface +MOZ_CAN_RUN_SCRIPT +extern "C" int UniFFIFixturesCallbackHandlerLogger(uint64_t aHandle, uint32_t aMethod, const uint8_t* aArgsData, int32_t aArgsLen, RustBuffer* aOutBuffer) { + // Currently, we only support "fire-and-forget" async callbacks. These are + // callbacks that run asynchronously without returning anything. The main + // use case for callbacks is logging, which fits very well with this model. + // + // So, here we simple queue the callback and return immediately. + mozilla::uniffi::QueueCallback(0, aHandle, aMethod, aArgsData, aArgsLen); + return CALLBACK_INTERFACE_SUCCESS; +} +static StaticRefPtr JS_CALLBACK_HANDLER_LOGGER; // Define a lookup function for our callback interface info Maybe UniFFIFixturesGetCallbackInterfaceInfo(uint64_t aInterfaceId) { switch(aInterfaceId) { + case 0: { // fixture_callbacks:Logger + return Some(CallbackInterfaceInfo { + "Logger", + &JS_CALLBACK_HANDLER_LOGGER, + UniFFIFixturesCallbackHandlerLogger, + uniffi_uniffi_fixture_callbacks_fn_init_callback_logger, + }); + } default: return Nothing(); @@ -166,383 +178,371 @@ Maybe UniFFIFixturesGetCallbackInterfaceInfo(uint64_t aIn Maybe> UniFFIFixturesCallAsync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, ErrorResult& aError) { switch (aId) { - case 47: { // arithmetic:uniffi_arithmetical_fn_func_add + case 39: { // arithmetic:uniffi_arithmetical_fn_func_add using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_arithmetical_fn_func_add, aGlobal, aArgs, "uniffi_arithmetical_fn_func_add: "_ns, aError)); } - case 48: { // arithmetic:uniffi_arithmetical_fn_func_div + case 40: { // arithmetic:uniffi_arithmetical_fn_func_div using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_arithmetical_fn_func_div, aGlobal, aArgs, "uniffi_arithmetical_fn_func_div: "_ns, aError)); } - case 49: { // arithmetic:uniffi_arithmetical_fn_func_equal + case 41: { // arithmetic:uniffi_arithmetical_fn_func_equal using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_arithmetical_fn_func_equal, aGlobal, aArgs, "uniffi_arithmetical_fn_func_equal: "_ns, aError)); } - case 50: { // arithmetic:uniffi_arithmetical_fn_func_sub + case 42: { // arithmetic:uniffi_arithmetical_fn_func_sub using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_arithmetical_fn_func_sub, aGlobal, aArgs, "uniffi_arithmetical_fn_func_sub: "_ns, aError)); } - case 51: { // custom_types:uniffi_uniffi_custom_types_fn_func_get_custom_types_demo + case 43: { // custom_types:uniffi_uniffi_custom_types_fn_func_get_custom_types_demo using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_custom_types_fn_func_get_custom_types_demo, aGlobal, aArgs, "uniffi_uniffi_custom_types_fn_func_get_custom_types_demo: "_ns, aError)); } - case 52: { // external_types:uniffi_uniffi_fixture_external_types_fn_func_gradient + case 44: { // external_types:uniffi_uniffi_fixture_external_types_fn_func_gradient using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_fixture_external_types_fn_func_gradient, aGlobal, aArgs, "uniffi_uniffi_fixture_external_types_fn_func_gradient: "_ns, aError)); } - case 53: { // external_types:uniffi_uniffi_fixture_external_types_fn_func_intersection + case 45: { // external_types:uniffi_uniffi_fixture_external_types_fn_func_intersection using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_fixture_external_types_fn_func_intersection, aGlobal, aArgs, "uniffi_uniffi_fixture_external_types_fn_func_intersection: "_ns, aError)); } - case 54: { // geometry:uniffi_uniffi_geometry_fn_func_gradient + case 46: { // fixture_callbacks:uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers, aGlobal, aArgs, "uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers: "_ns, aError)); + } + case 47: { // fixture_callbacks:uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers_main_thread + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers_main_thread, aGlobal, aArgs, "uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers_main_thread: "_ns, aError)); + } + case 48: { // geometry:uniffi_uniffi_geometry_fn_func_gradient using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_geometry_fn_func_gradient, aGlobal, aArgs, "uniffi_uniffi_geometry_fn_func_gradient: "_ns, aError)); } - case 55: { // geometry:uniffi_uniffi_geometry_fn_func_intersection + case 49: { // geometry:uniffi_uniffi_geometry_fn_func_intersection using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_geometry_fn_func_intersection, aGlobal, aArgs, "uniffi_uniffi_geometry_fn_func_intersection: "_ns, aError)); } - case 56: { // rondpoint:uniffi_uniffi_rondpoint_fn_clone_optionneur - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>>; - return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_clone_optionneur, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_clone_optionneur: "_ns, aError)); - } - case 57: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_optionneur_new + case 50: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_optionneur_new using CallHandler = ScaffoldingCallHandler>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_constructor_optionneur_new, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_constructor_optionneur_new: "_ns, aError)); } - case 58: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean + case 51: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean: "_ns, aError)); } - case 59: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum + case 52: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum: "_ns, aError)); } - case 60: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32 + case 53: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32: "_ns, aError)); } - case 61: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64 + case 54: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64: "_ns, aError)); } - case 62: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec + case 55: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec: "_ns, aError)); } - case 63: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex + case 56: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex: "_ns, aError)); } - case 64: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec + case 57: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec: "_ns, aError)); } - case 65: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex + case 58: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex: "_ns, aError)); } - case 66: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec + case 59: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec: "_ns, aError)); } - case 67: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex + case 60: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex: "_ns, aError)); } - case 68: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec + case 61: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec: "_ns, aError)); } - case 69: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex + case 62: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex: "_ns, aError)); } - case 70: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null + case 63: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null: "_ns, aError)); } - case 71: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence + case 64: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence: "_ns, aError)); } - case 72: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string + case 65: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string: "_ns, aError)); } - case 73: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec + case 66: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec: "_ns, aError)); } - case 74: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex + case 67: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex: "_ns, aError)); } - case 75: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec + case 68: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec: "_ns, aError)); } - case 76: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex + case 69: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex: "_ns, aError)); } - case 77: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct + case 70: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct: "_ns, aError)); } - case 78: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec + case 71: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec: "_ns, aError)); } - case 79: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex + case 72: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex: "_ns, aError)); } - case 80: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec + case 73: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec: "_ns, aError)); } - case 81: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex + case 74: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex: "_ns, aError)); } - case 82: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero + case 75: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero: "_ns, aError)); } - case 83: { // rondpoint:uniffi_uniffi_rondpoint_fn_clone_retourneur - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>>; - return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_clone_retourneur, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_clone_retourneur: "_ns, aError)); - } - case 84: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_retourneur_new + case 76: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_retourneur_new using CallHandler = ScaffoldingCallHandler>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_constructor_retourneur_new, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_constructor_retourneur_new: "_ns, aError)); } - case 85: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean + case 77: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean: "_ns, aError)); } - case 86: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double + case 78: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double: "_ns, aError)); } - case 87: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float + case 79: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float: "_ns, aError)); } - case 88: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16 + case 80: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16: "_ns, aError)); } - case 89: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32 + case 81: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32: "_ns, aError)); } - case 90: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64 + case 82: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64: "_ns, aError)); } - case 91: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8 + case 83: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8: "_ns, aError)); } - case 92: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres + case 84: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres: "_ns, aError)); } - case 93: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes + case 85: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes: "_ns, aError)); } - case 94: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire + case 86: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire: "_ns, aError)); } - case 95: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string + case 87: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string: "_ns, aError)); } - case 96: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16 + case 88: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16: "_ns, aError)); } - case 97: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32 + case 89: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32: "_ns, aError)); } - case 98: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64 + case 90: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64: "_ns, aError)); } - case 99: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8 + case 91: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8: "_ns, aError)); } - case 100: { // rondpoint:uniffi_uniffi_rondpoint_fn_clone_stringifier - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>>; - return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_clone_stringifier, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_clone_stringifier: "_ns, aError)); - } - case 101: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_stringifier_new + case 92: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_stringifier_new using CallHandler = ScaffoldingCallHandler>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_constructor_stringifier_new, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_constructor_stringifier_new: "_ns, aError)); } - case 102: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean + case 93: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean: "_ns, aError)); } - case 103: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double + case 94: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double: "_ns, aError)); } - case 104: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float + case 95: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float: "_ns, aError)); } - case 105: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16 + case 96: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16: "_ns, aError)); } - case 106: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32 + case 97: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32: "_ns, aError)); } - case 107: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64 + case 98: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64: "_ns, aError)); } - case 108: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8 + case 99: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8: "_ns, aError)); } - case 109: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16 + case 100: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16: "_ns, aError)); } - case 110: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32 + case 101: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32: "_ns, aError)); } - case 111: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64 + case 102: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64: "_ns, aError)); } - case 112: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8 + case 103: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8: "_ns, aError)); } - case 113: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string + case 104: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string: "_ns, aError)); } - case 114: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_carte + case 105: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_carte using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_func_copie_carte, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_func_copie_carte: "_ns, aError)); } - case 115: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire + case 106: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire: "_ns, aError)); } - case 116: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumeration + case 107: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumeration using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_func_copie_enumeration, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_func_copie_enumeration: "_ns, aError)); } - case 117: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumerations + case 108: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumerations using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_func_copie_enumerations, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_func_copie_enumerations: "_ns, aError)); } - case 118: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_switcheroo + case 109: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_switcheroo using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_rondpoint_fn_func_switcheroo, aGlobal, aArgs, "uniffi_uniffi_rondpoint_fn_func_switcheroo: "_ns, aError)); } - case 119: { // sprites:uniffi_uniffi_sprites_fn_clone_sprite - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>>; - return Some(CallHandler::CallAsync(uniffi_uniffi_sprites_fn_clone_sprite, aGlobal, aArgs, "uniffi_uniffi_sprites_fn_clone_sprite: "_ns, aError)); - } - case 120: { // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new + case 110: { // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_sprites_fn_constructor_sprite_new, aGlobal, aArgs, "uniffi_uniffi_sprites_fn_constructor_sprite_new: "_ns, aError)); } - case 121: { // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to + case 111: { // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to, aGlobal, aArgs, "uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to: "_ns, aError)); } - case 122: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_get_position + case 112: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_get_position using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>>; return Some(CallHandler::CallAsync(uniffi_uniffi_sprites_fn_method_sprite_get_position, aGlobal, aArgs, "uniffi_uniffi_sprites_fn_method_sprite_get_position: "_ns, aError)); } - case 123: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_by + case 113: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_by using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_sprites_fn_method_sprite_move_by, aGlobal, aArgs, "uniffi_uniffi_sprites_fn_method_sprite_move_by: "_ns, aError)); } - case 124: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_to + case 114: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_to using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_sprites_fn_method_sprite_move_to, aGlobal, aArgs, "uniffi_uniffi_sprites_fn_method_sprite_move_to: "_ns, aError)); } - case 125: { // sprites:uniffi_uniffi_sprites_fn_func_translate + case 115: { // sprites:uniffi_uniffi_sprites_fn_func_translate using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_sprites_fn_func_translate, aGlobal, aArgs, "uniffi_uniffi_sprites_fn_func_translate: "_ns, aError)); } - case 126: { // todolist:uniffi_uniffi_todolist_fn_clone_todolist - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; - return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_clone_todolist, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_clone_todolist: "_ns, aError)); - } - case 127: { // todolist:uniffi_uniffi_todolist_fn_constructor_todolist_new + case 116: { // todolist:uniffi_uniffi_todolist_fn_constructor_todolist_new using CallHandler = ScaffoldingCallHandler>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_constructor_todolist_new, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_constructor_todolist_new: "_ns, aError)); } - case 128: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entries + case 117: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entries using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_add_entries, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_add_entries: "_ns, aError)); } - case 129: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entry + case 118: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entry using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_add_entry, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_add_entry: "_ns, aError)); } - case 130: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_item + case 119: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_item using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_add_item, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_add_item: "_ns, aError)); } - case 131: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_items + case 120: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_items using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_add_items, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_add_items: "_ns, aError)); } - case 132: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_clear_item + case 121: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_clear_item using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_clear_item, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_clear_item: "_ns, aError)); } - case 133: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_entries + case 122: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_entries using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_get_entries, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_get_entries: "_ns, aError)); } - case 134: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_first + case 123: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_first using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_get_first, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_get_first: "_ns, aError)); } - case 135: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_items + case 124: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_items using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_get_items, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_get_items: "_ns, aError)); } - case 136: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last + case 125: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_get_last, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_get_last: "_ns, aError)); } - case 137: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last_entry + case 126: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last_entry using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_get_last_entry, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_get_last_entry: "_ns, aError)); } - case 138: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_make_default + case 127: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_make_default using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_method_todolist_make_default, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_method_todolist_make_default: "_ns, aError)); } - case 139: { // todolist:uniffi_uniffi_todolist_fn_func_create_entry_with + case 128: { // todolist:uniffi_uniffi_todolist_fn_func_create_entry_with using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_func_create_entry_with, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_func_create_entry_with: "_ns, aError)); } - case 140: { // todolist:uniffi_uniffi_todolist_fn_func_get_default_list + case 129: { // todolist:uniffi_uniffi_todolist_fn_func_get_default_list using CallHandler = ScaffoldingCallHandler>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_func_get_default_list, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_func_get_default_list: "_ns, aError)); } - case 141: { // todolist:uniffi_uniffi_todolist_fn_func_set_default_list + case 130: { // todolist:uniffi_uniffi_todolist_fn_func_set_default_list using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; return Some(CallHandler::CallAsync(uniffi_uniffi_todolist_fn_func_set_default_list, aGlobal, aArgs, "uniffi_uniffi_todolist_fn_func_set_default_list: "_ns, aError)); } @@ -552,477 +552,462 @@ Maybe> UniFFIFixturesCallAsync(const GlobalObject& aGl bool UniFFIFixturesCallSync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, RootedDictionary& aReturnValue, ErrorResult& aError) { switch (aId) { - case 47: { // arithmetic:uniffi_arithmetical_fn_func_add + case 39: { // arithmetic:uniffi_arithmetical_fn_func_add using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_arithmetical_fn_func_add, aGlobal, aArgs, aReturnValue, "uniffi_arithmetical_fn_func_add: "_ns, aError); return true; } - case 48: { // arithmetic:uniffi_arithmetical_fn_func_div + case 40: { // arithmetic:uniffi_arithmetical_fn_func_div using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_arithmetical_fn_func_div, aGlobal, aArgs, aReturnValue, "uniffi_arithmetical_fn_func_div: "_ns, aError); return true; } - case 49: { // arithmetic:uniffi_arithmetical_fn_func_equal + case 41: { // arithmetic:uniffi_arithmetical_fn_func_equal using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_arithmetical_fn_func_equal, aGlobal, aArgs, aReturnValue, "uniffi_arithmetical_fn_func_equal: "_ns, aError); return true; } - case 50: { // arithmetic:uniffi_arithmetical_fn_func_sub + case 42: { // arithmetic:uniffi_arithmetical_fn_func_sub using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_arithmetical_fn_func_sub, aGlobal, aArgs, aReturnValue, "uniffi_arithmetical_fn_func_sub: "_ns, aError); return true; } - case 51: { // custom_types:uniffi_uniffi_custom_types_fn_func_get_custom_types_demo + case 43: { // custom_types:uniffi_uniffi_custom_types_fn_func_get_custom_types_demo using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_custom_types_fn_func_get_custom_types_demo, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_custom_types_fn_func_get_custom_types_demo: "_ns, aError); return true; } - case 52: { // external_types:uniffi_uniffi_fixture_external_types_fn_func_gradient + case 44: { // external_types:uniffi_uniffi_fixture_external_types_fn_func_gradient using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_fixture_external_types_fn_func_gradient, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_fixture_external_types_fn_func_gradient: "_ns, aError); return true; } - case 53: { // external_types:uniffi_uniffi_fixture_external_types_fn_func_intersection + case 45: { // external_types:uniffi_uniffi_fixture_external_types_fn_func_intersection using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_fixture_external_types_fn_func_intersection, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_fixture_external_types_fn_func_intersection: "_ns, aError); return true; } - case 54: { // geometry:uniffi_uniffi_geometry_fn_func_gradient + case 46: { // fixture_callbacks:uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + CallHandler::CallSync(uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers: "_ns, aError); + return true; + } + case 47: { // fixture_callbacks:uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers_main_thread + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + CallHandler::CallSync(uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers_main_thread, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers_main_thread: "_ns, aError); + return true; + } + case 48: { // geometry:uniffi_uniffi_geometry_fn_func_gradient using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_geometry_fn_func_gradient, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_geometry_fn_func_gradient: "_ns, aError); return true; } - case 55: { // geometry:uniffi_uniffi_geometry_fn_func_intersection + case 49: { // geometry:uniffi_uniffi_geometry_fn_func_intersection using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_geometry_fn_func_intersection, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_geometry_fn_func_intersection: "_ns, aError); return true; } - case 56: { // rondpoint:uniffi_uniffi_rondpoint_fn_clone_optionneur - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>>; - CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_clone_optionneur, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_clone_optionneur: "_ns, aError); - return true; - } - case 57: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_optionneur_new + case 50: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_optionneur_new using CallHandler = ScaffoldingCallHandler>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_constructor_optionneur_new, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_constructor_optionneur_new: "_ns, aError); return true; } - case 58: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean + case 51: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean: "_ns, aError); return true; } - case 59: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum + case 52: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum: "_ns, aError); return true; } - case 60: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32 + case 53: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f32: "_ns, aError); return true; } - case 61: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64 + case 54: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64: "_ns, aError); return true; } - case 62: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec + case 55: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_dec: "_ns, aError); return true; } - case 63: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex + case 56: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i16_hex: "_ns, aError); return true; } - case 64: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec + case 57: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_dec: "_ns, aError); return true; } - case 65: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex + case 58: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i32_hex: "_ns, aError); return true; } - case 66: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec + case 59: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_dec: "_ns, aError); return true; } - case 67: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex + case 60: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i64_hex: "_ns, aError); return true; } - case 68: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec + case 61: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_dec: "_ns, aError); return true; } - case 69: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex + case 62: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_i8_hex: "_ns, aError); return true; } - case 70: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null + case 63: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null: "_ns, aError); return true; } - case 71: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence + case 64: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence: "_ns, aError); return true; } - case 72: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string + case 65: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string: "_ns, aError); return true; } - case 73: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec + case 66: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_dec: "_ns, aError); return true; } - case 74: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex + case 67: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u16_hex: "_ns, aError); return true; } - case 75: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec + case 68: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_dec: "_ns, aError); return true; } - case 76: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex + case 69: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_hex: "_ns, aError); return true; } - case 77: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct + case 70: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u32_oct: "_ns, aError); return true; } - case 78: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec + case 71: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_dec: "_ns, aError); return true; } - case 79: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex + case 72: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u64_hex: "_ns, aError); return true; } - case 80: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec + case 73: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_dec: "_ns, aError); return true; } - case 81: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex + case 74: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_u8_hex: "_ns, aError); return true; } - case 82: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero + case 75: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero: "_ns, aError); return true; } - case 83: { // rondpoint:uniffi_uniffi_rondpoint_fn_clone_retourneur - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>>; - CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_clone_retourneur, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_clone_retourneur: "_ns, aError); - return true; - } - case 84: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_retourneur_new + case 76: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_retourneur_new using CallHandler = ScaffoldingCallHandler>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_constructor_retourneur_new, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_constructor_retourneur_new: "_ns, aError); return true; } - case 85: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean + case 77: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean: "_ns, aError); return true; } - case 86: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double + case 78: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double: "_ns, aError); return true; } - case 87: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float + case 79: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float: "_ns, aError); return true; } - case 88: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16 + case 80: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16: "_ns, aError); return true; } - case 89: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32 + case 81: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32: "_ns, aError); return true; } - case 90: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64 + case 82: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64: "_ns, aError); return true; } - case 91: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8 + case 83: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8: "_ns, aError); return true; } - case 92: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres + case 84: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres: "_ns, aError); return true; } - case 93: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes + case 85: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres_signes: "_ns, aError); return true; } - case 94: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire + case 86: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_optionneur_dictionnaire: "_ns, aError); return true; } - case 95: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string + case 87: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string: "_ns, aError); return true; } - case 96: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16 + case 88: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16: "_ns, aError); return true; } - case 97: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32 + case 89: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32: "_ns, aError); return true; } - case 98: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64 + case 90: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64: "_ns, aError); return true; } - case 99: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8 + case 91: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8: "_ns, aError); return true; } - case 100: { // rondpoint:uniffi_uniffi_rondpoint_fn_clone_stringifier - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>>; - CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_clone_stringifier, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_clone_stringifier: "_ns, aError); - return true; - } - case 101: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_stringifier_new + case 92: { // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_stringifier_new using CallHandler = ScaffoldingCallHandler>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_constructor_stringifier_new, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_constructor_stringifier_new: "_ns, aError); return true; } - case 102: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean + case 93: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_boolean: "_ns, aError); return true; } - case 103: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double + case 94: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_double: "_ns, aError); return true; } - case 104: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float + case 95: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_float: "_ns, aError); return true; } - case 105: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16 + case 96: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i16: "_ns, aError); return true; } - case 106: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32 + case 97: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i32: "_ns, aError); return true; } - case 107: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64 + case 98: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i64: "_ns, aError); return true; } - case 108: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8 + case 99: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_i8: "_ns, aError); return true; } - case 109: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16 + case 100: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u16: "_ns, aError); return true; } - case 110: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32 + case 101: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u32: "_ns, aError); return true; } - case 111: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64 + case 102: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u64: "_ns, aError); return true; } - case 112: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8 + case 103: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8 using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_to_string_u8: "_ns, aError); return true; } - case 113: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string + case 104: { // rondpoint:uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_method_stringifier_well_known_string: "_ns, aError); return true; } - case 114: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_carte + case 105: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_carte using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_func_copie_carte, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_func_copie_carte: "_ns, aError); return true; } - case 115: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire + case 106: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_func_copie_dictionnaire: "_ns, aError); return true; } - case 116: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumeration + case 107: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumeration using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_func_copie_enumeration, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_func_copie_enumeration: "_ns, aError); return true; } - case 117: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumerations + case 108: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumerations using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_func_copie_enumerations, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_func_copie_enumerations: "_ns, aError); return true; } - case 118: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_switcheroo + case 109: { // rondpoint:uniffi_uniffi_rondpoint_fn_func_switcheroo using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_rondpoint_fn_func_switcheroo, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_rondpoint_fn_func_switcheroo: "_ns, aError); return true; } - case 119: { // sprites:uniffi_uniffi_sprites_fn_clone_sprite - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>>; - CallHandler::CallSync(uniffi_uniffi_sprites_fn_clone_sprite, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_sprites_fn_clone_sprite: "_ns, aError); - return true; - } - case 120: { // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new + case 110: { // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_sprites_fn_constructor_sprite_new, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_sprites_fn_constructor_sprite_new: "_ns, aError); return true; } - case 121: { // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to + case 111: { // sprites:uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_sprites_fn_constructor_sprite_new_relative_to: "_ns, aError); return true; } - case 122: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_get_position + case 112: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_get_position using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>>; CallHandler::CallSync(uniffi_uniffi_sprites_fn_method_sprite_get_position, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_sprites_fn_method_sprite_get_position: "_ns, aError); return true; } - case 123: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_by + case 113: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_by using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_sprites_fn_method_sprite_move_by, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_sprites_fn_method_sprite_move_by: "_ns, aError); return true; } - case 124: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_to + case 114: { // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_to using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_sprites_fn_method_sprite_move_to, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_sprites_fn_method_sprite_move_to: "_ns, aError); return true; } - case 125: { // sprites:uniffi_uniffi_sprites_fn_func_translate + case 115: { // sprites:uniffi_uniffi_sprites_fn_func_translate using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_sprites_fn_func_translate, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_sprites_fn_func_translate: "_ns, aError); return true; } - case 126: { // todolist:uniffi_uniffi_todolist_fn_clone_todolist - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; - CallHandler::CallSync(uniffi_uniffi_todolist_fn_clone_todolist, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_clone_todolist: "_ns, aError); - return true; - } - case 127: { // todolist:uniffi_uniffi_todolist_fn_constructor_todolist_new + case 116: { // todolist:uniffi_uniffi_todolist_fn_constructor_todolist_new using CallHandler = ScaffoldingCallHandler>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_constructor_todolist_new, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_constructor_todolist_new: "_ns, aError); return true; } - case 128: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entries + case 117: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entries using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_add_entries, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_add_entries: "_ns, aError); return true; } - case 129: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entry + case 118: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entry using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_add_entry, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_add_entry: "_ns, aError); return true; } - case 130: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_item + case 119: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_item using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_add_item, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_add_item: "_ns, aError); return true; } - case 131: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_items + case 120: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_items using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_add_items, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_add_items: "_ns, aError); return true; } - case 132: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_clear_item + case 121: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_clear_item using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_clear_item, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_clear_item: "_ns, aError); return true; } - case 133: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_entries + case 122: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_entries using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_get_entries, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_get_entries: "_ns, aError); return true; } - case 134: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_first + case 123: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_first using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_get_first, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_get_first: "_ns, aError); return true; } - case 135: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_items + case 124: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_items using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_get_items, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_get_items: "_ns, aError); return true; } - case 136: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last + case 125: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_get_last, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_get_last: "_ns, aError); return true; } - case 137: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last_entry + case 126: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last_entry using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_get_last_entry, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_get_last_entry: "_ns, aError); return true; } - case 138: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_make_default + case 127: { // todolist:uniffi_uniffi_todolist_fn_method_todolist_make_default using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_method_todolist_make_default, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_method_todolist_make_default: "_ns, aError); return true; } - case 139: { // todolist:uniffi_uniffi_todolist_fn_func_create_entry_with + case 128: { // todolist:uniffi_uniffi_todolist_fn_func_create_entry_with using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_func_create_entry_with, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_func_create_entry_with: "_ns, aError); return true; } - case 140: { // todolist:uniffi_uniffi_todolist_fn_func_get_default_list + case 129: { // todolist:uniffi_uniffi_todolist_fn_func_get_default_list using CallHandler = ScaffoldingCallHandler>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_func_get_default_list, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_func_get_default_list: "_ns, aError); return true; } - case 141: { // todolist:uniffi_uniffi_todolist_fn_func_set_default_list + case 130: { // todolist:uniffi_uniffi_todolist_fn_func_set_default_list using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; CallHandler::CallSync(uniffi_uniffi_todolist_fn_func_set_default_list, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_todolist_fn_func_set_default_list: "_ns, aError); return true; diff --git a/toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp b/toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp index 20a581d5e2c2..c4881ac79d52 100644 --- a/toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp +++ b/toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp @@ -24,30 +24,24 @@ using dom::UniFFIScaffoldingCallResult; // Define scaffolding functions from UniFFI extern "C" { - void * uniffi_relevancy_fn_clone_relevancystore(void *, RustCallStatus*); void uniffi_relevancy_fn_free_relevancystore(void *, RustCallStatus*); void * uniffi_relevancy_fn_constructor_relevancystore_new(RustBuffer, RustCallStatus*); RustBuffer uniffi_relevancy_fn_method_relevancystore_calculate_metrics(void *, RustCallStatus*); void uniffi_relevancy_fn_method_relevancystore_ingest(void *, RustBuffer, RustCallStatus*); RustBuffer uniffi_relevancy_fn_method_relevancystore_user_interest_vector(void *, RustCallStatus*); - void * uniffi_remote_settings_fn_clone_remotesettings(void *, RustCallStatus*); void uniffi_remote_settings_fn_free_remotesettings(void *, RustCallStatus*); void * uniffi_remote_settings_fn_constructor_remotesettings_new(RustBuffer, RustCallStatus*); void uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path(void *, RustBuffer, RustBuffer, RustCallStatus*); RustBuffer uniffi_remote_settings_fn_method_remotesettings_get_records(void *, RustCallStatus*); RustBuffer uniffi_remote_settings_fn_method_remotesettings_get_records_since(void *, uint64_t, RustCallStatus*); - void * uniffi_suggest_fn_clone_suggeststore(void *, RustCallStatus*); void uniffi_suggest_fn_free_suggeststore(void *, RustCallStatus*); void * uniffi_suggest_fn_constructor_suggeststore_new(RustBuffer, RustBuffer, RustCallStatus*); void uniffi_suggest_fn_method_suggeststore_clear(void *, RustCallStatus*); - void uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions(void *, RustCallStatus*); - void uniffi_suggest_fn_method_suggeststore_dismiss_suggestion(void *, RustBuffer, RustCallStatus*); RustBuffer uniffi_suggest_fn_method_suggeststore_fetch_global_config(void *, RustCallStatus*); RustBuffer uniffi_suggest_fn_method_suggeststore_fetch_provider_config(void *, RustBuffer, RustCallStatus*); void uniffi_suggest_fn_method_suggeststore_ingest(void *, RustBuffer, RustCallStatus*); void uniffi_suggest_fn_method_suggeststore_interrupt(void *, RustCallStatus*); RustBuffer uniffi_suggest_fn_method_suggeststore_query(void *, RustBuffer, RustCallStatus*); - void * uniffi_suggest_fn_clone_suggeststorebuilder(void *, RustCallStatus*); void uniffi_suggest_fn_free_suggeststorebuilder(void *, RustCallStatus*); void * uniffi_suggest_fn_constructor_suggeststorebuilder_new(RustCallStatus*); void * uniffi_suggest_fn_method_suggeststorebuilder_build(void *, RustCallStatus*); @@ -55,7 +49,6 @@ extern "C" { void * uniffi_suggest_fn_method_suggeststorebuilder_data_path(void *, RustBuffer, RustCallStatus*); void * uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config(void *, RustBuffer, RustCallStatus*); int8_t uniffi_suggest_fn_func_raw_suggestion_url_matches(RustBuffer, RustBuffer, RustCallStatus*); - void * uniffi_tabs_fn_clone_tabsbridgedengine(void *, RustCallStatus*); void uniffi_tabs_fn_free_tabsbridgedengine(void *, RustCallStatus*); RustBuffer uniffi_tabs_fn_method_tabsbridgedengine_apply(void *, RustCallStatus*); RustBuffer uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id(void *, RustBuffer, RustCallStatus*); @@ -70,7 +63,6 @@ extern "C" { RustBuffer uniffi_tabs_fn_method_tabsbridgedengine_sync_id(void *, RustCallStatus*); void uniffi_tabs_fn_method_tabsbridgedengine_sync_started(void *, RustCallStatus*); void uniffi_tabs_fn_method_tabsbridgedengine_wipe(void *, RustCallStatus*); - void * uniffi_tabs_fn_clone_tabsstore(void *, RustCallStatus*); void uniffi_tabs_fn_free_tabsstore(void *, RustCallStatus*); void * uniffi_tabs_fn_constructor_tabsstore_new(RustBuffer, RustCallStatus*); void * uniffi_tabs_fn_method_tabsstore_bridged_engine(void *, RustCallStatus*); @@ -82,33 +74,27 @@ extern "C" { // Define pointer types const static mozilla::uniffi::UniFFIPointerType kRelevancyRelevancyStorePointerType { "relevancy::RelevancyStore"_ns, - uniffi_relevancy_fn_clone_relevancystore, - uniffi_relevancy_fn_free_relevancystore, + uniffi_relevancy_fn_free_relevancystore }; const static mozilla::uniffi::UniFFIPointerType kRemoteSettingsRemoteSettingsPointerType { "remote_settings::RemoteSettings"_ns, - uniffi_remote_settings_fn_clone_remotesettings, - uniffi_remote_settings_fn_free_remotesettings, + uniffi_remote_settings_fn_free_remotesettings }; const static mozilla::uniffi::UniFFIPointerType kSuggestSuggestStorePointerType { "suggest::SuggestStore"_ns, - uniffi_suggest_fn_clone_suggeststore, - uniffi_suggest_fn_free_suggeststore, + uniffi_suggest_fn_free_suggeststore }; const static mozilla::uniffi::UniFFIPointerType kSuggestSuggestStoreBuilderPointerType { "suggest::SuggestStoreBuilder"_ns, - uniffi_suggest_fn_clone_suggeststorebuilder, - uniffi_suggest_fn_free_suggeststorebuilder, + uniffi_suggest_fn_free_suggeststorebuilder }; const static mozilla::uniffi::UniFFIPointerType kTabsTabsBridgedEnginePointerType { "tabs::TabsBridgedEngine"_ns, - uniffi_tabs_fn_clone_tabsbridgedengine, - uniffi_tabs_fn_free_tabsbridgedengine, + uniffi_tabs_fn_free_tabsbridgedengine }; const static mozilla::uniffi::UniFFIPointerType kTabsTabsStorePointerType { "tabs::TabsStore"_ns, - uniffi_tabs_fn_clone_tabsstore, - uniffi_tabs_fn_free_tabsstore, + uniffi_tabs_fn_free_tabsstore }; // Define the data we need per-callback interface @@ -124,191 +110,159 @@ Maybe UniFFIGetCallbackInterfaceInfo(uint64_t aInterfaceI Maybe> UniFFICallAsync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, ErrorResult& aError) { switch (aId) { - case 0: { // relevancy:uniffi_relevancy_fn_clone_relevancystore - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRelevancyRelevancyStorePointerType>>; - return Some(CallHandler::CallAsync(uniffi_relevancy_fn_clone_relevancystore, aGlobal, aArgs, "uniffi_relevancy_fn_clone_relevancystore: "_ns, aError)); - } - case 1: { // relevancy:uniffi_relevancy_fn_constructor_relevancystore_new + case 0: { // relevancy:uniffi_relevancy_fn_constructor_relevancystore_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_relevancy_fn_constructor_relevancystore_new, aGlobal, aArgs, "uniffi_relevancy_fn_constructor_relevancystore_new: "_ns, aError)); } - case 2: { // relevancy:uniffi_relevancy_fn_method_relevancystore_calculate_metrics + case 1: { // relevancy:uniffi_relevancy_fn_method_relevancystore_calculate_metrics using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRelevancyRelevancyStorePointerType>>; return Some(CallHandler::CallAsync(uniffi_relevancy_fn_method_relevancystore_calculate_metrics, aGlobal, aArgs, "uniffi_relevancy_fn_method_relevancystore_calculate_metrics: "_ns, aError)); } - case 3: { // relevancy:uniffi_relevancy_fn_method_relevancystore_ingest + case 2: { // relevancy:uniffi_relevancy_fn_method_relevancystore_ingest using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRelevancyRelevancyStorePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_relevancy_fn_method_relevancystore_ingest, aGlobal, aArgs, "uniffi_relevancy_fn_method_relevancystore_ingest: "_ns, aError)); } - case 4: { // relevancy:uniffi_relevancy_fn_method_relevancystore_user_interest_vector + case 3: { // relevancy:uniffi_relevancy_fn_method_relevancystore_user_interest_vector using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRelevancyRelevancyStorePointerType>>; return Some(CallHandler::CallAsync(uniffi_relevancy_fn_method_relevancystore_user_interest_vector, aGlobal, aArgs, "uniffi_relevancy_fn_method_relevancystore_user_interest_vector: "_ns, aError)); } - case 5: { // remote_settings:uniffi_remote_settings_fn_clone_remotesettings - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRemoteSettingsRemoteSettingsPointerType>>; - return Some(CallHandler::CallAsync(uniffi_remote_settings_fn_clone_remotesettings, aGlobal, aArgs, "uniffi_remote_settings_fn_clone_remotesettings: "_ns, aError)); - } - case 6: { // remote_settings:uniffi_remote_settings_fn_constructor_remotesettings_new + case 4: { // remote_settings:uniffi_remote_settings_fn_constructor_remotesettings_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_remote_settings_fn_constructor_remotesettings_new, aGlobal, aArgs, "uniffi_remote_settings_fn_constructor_remotesettings_new: "_ns, aError)); } - case 7: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path + case 5: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRemoteSettingsRemoteSettingsPointerType>, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path, aGlobal, aArgs, "uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path: "_ns, aError)); } - case 8: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records + case 6: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRemoteSettingsRemoteSettingsPointerType>>; return Some(CallHandler::CallAsync(uniffi_remote_settings_fn_method_remotesettings_get_records, aGlobal, aArgs, "uniffi_remote_settings_fn_method_remotesettings_get_records: "_ns, aError)); } - case 9: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records_since + case 7: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records_since using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRemoteSettingsRemoteSettingsPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_remote_settings_fn_method_remotesettings_get_records_since, aGlobal, aArgs, "uniffi_remote_settings_fn_method_remotesettings_get_records_since: "_ns, aError)); } - case 10: { // suggest:uniffi_suggest_fn_clone_suggeststore - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; - return Some(CallHandler::CallAsync(uniffi_suggest_fn_clone_suggeststore, aGlobal, aArgs, "uniffi_suggest_fn_clone_suggeststore: "_ns, aError)); - } - case 11: { // suggest:uniffi_suggest_fn_constructor_suggeststore_new + case 8: { // suggest:uniffi_suggest_fn_constructor_suggeststore_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_constructor_suggeststore_new, aGlobal, aArgs, "uniffi_suggest_fn_constructor_suggeststore_new: "_ns, aError)); } - case 12: { // suggest:uniffi_suggest_fn_method_suggeststore_clear + case 9: { // suggest:uniffi_suggest_fn_method_suggeststore_clear using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststore_clear, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststore_clear: "_ns, aError)); } - case 13: { // suggest:uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; - return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions: "_ns, aError)); - } - case 14: { // suggest:uniffi_suggest_fn_method_suggeststore_dismiss_suggestion - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>, ScaffoldingConverter>; - return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststore_dismiss_suggestion, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststore_dismiss_suggestion: "_ns, aError)); - } - case 15: { // suggest:uniffi_suggest_fn_method_suggeststore_fetch_global_config + case 10: { // suggest:uniffi_suggest_fn_method_suggeststore_fetch_global_config using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststore_fetch_global_config, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststore_fetch_global_config: "_ns, aError)); } - case 16: { // suggest:uniffi_suggest_fn_method_suggeststore_fetch_provider_config + case 11: { // suggest:uniffi_suggest_fn_method_suggeststore_fetch_provider_config using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststore_fetch_provider_config, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststore_fetch_provider_config: "_ns, aError)); } - case 17: { // suggest:uniffi_suggest_fn_method_suggeststore_ingest + case 12: { // suggest:uniffi_suggest_fn_method_suggeststore_ingest using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststore_ingest, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststore_ingest: "_ns, aError)); } - case 18: { // suggest:uniffi_suggest_fn_method_suggeststore_interrupt + case 13: { // suggest:uniffi_suggest_fn_method_suggeststore_interrupt using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststore_interrupt, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststore_interrupt: "_ns, aError)); } - case 19: { // suggest:uniffi_suggest_fn_method_suggeststore_query + case 14: { // suggest:uniffi_suggest_fn_method_suggeststore_query using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststore_query, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststore_query: "_ns, aError)); } - case 20: { // suggest:uniffi_suggest_fn_clone_suggeststorebuilder - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>>; - return Some(CallHandler::CallAsync(uniffi_suggest_fn_clone_suggeststorebuilder, aGlobal, aArgs, "uniffi_suggest_fn_clone_suggeststorebuilder: "_ns, aError)); - } - case 21: { // suggest:uniffi_suggest_fn_constructor_suggeststorebuilder_new + case 15: { // suggest:uniffi_suggest_fn_constructor_suggeststorebuilder_new using CallHandler = ScaffoldingCallHandler>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_constructor_suggeststorebuilder_new, aGlobal, aArgs, "uniffi_suggest_fn_constructor_suggeststorebuilder_new: "_ns, aError)); } - case 22: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_build + case 16: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_build using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststorebuilder_build, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststorebuilder_build: "_ns, aError)); } - case 23: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_cache_path + case 17: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_cache_path using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststorebuilder_cache_path, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststorebuilder_cache_path: "_ns, aError)); } - case 24: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_data_path + case 18: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_data_path using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststorebuilder_data_path, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststorebuilder_data_path: "_ns, aError)); } - case 25: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config + case 19: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config, aGlobal, aArgs, "uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config: "_ns, aError)); } - case 26: { // suggest:uniffi_suggest_fn_func_raw_suggestion_url_matches + case 20: { // suggest:uniffi_suggest_fn_func_raw_suggestion_url_matches using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_suggest_fn_func_raw_suggestion_url_matches, aGlobal, aArgs, "uniffi_suggest_fn_func_raw_suggestion_url_matches: "_ns, aError)); } - case 27: { // tabs:uniffi_tabs_fn_clone_tabsbridgedengine - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; - return Some(CallHandler::CallAsync(uniffi_tabs_fn_clone_tabsbridgedengine, aGlobal, aArgs, "uniffi_tabs_fn_clone_tabsbridgedengine: "_ns, aError)); - } - case 28: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_apply + case 21: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_apply using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_apply, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_apply: "_ns, aError)); } - case 29: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id + case 22: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id: "_ns, aError)); } - case 30: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_last_sync + case 23: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_last_sync using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_last_sync, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_last_sync: "_ns, aError)); } - case 31: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync + case 24: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync: "_ns, aError)); } - case 32: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset + case 25: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_reset, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_reset: "_ns, aError)); } - case 33: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id + case 26: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id: "_ns, aError)); } - case 34: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync + case 27: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync: "_ns, aError)); } - case 35: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded + case 28: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded: "_ns, aError)); } - case 36: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_store_incoming + case 29: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_store_incoming using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_store_incoming, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_store_incoming: "_ns, aError)); } - case 37: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_finished + case 30: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_finished using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_sync_finished, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_sync_finished: "_ns, aError)); } - case 38: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_id + case 31: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_id using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_sync_id, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_sync_id: "_ns, aError)); } - case 39: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_started + case 32: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_started using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_sync_started, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_sync_started: "_ns, aError)); } - case 40: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_wipe + case 33: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_wipe using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsbridgedengine_wipe, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsbridgedengine_wipe: "_ns, aError)); } - case 41: { // tabs:uniffi_tabs_fn_clone_tabsstore - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>>; - return Some(CallHandler::CallAsync(uniffi_tabs_fn_clone_tabsstore, aGlobal, aArgs, "uniffi_tabs_fn_clone_tabsstore: "_ns, aError)); - } - case 42: { // tabs:uniffi_tabs_fn_constructor_tabsstore_new + case 34: { // tabs:uniffi_tabs_fn_constructor_tabsstore_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_constructor_tabsstore_new, aGlobal, aArgs, "uniffi_tabs_fn_constructor_tabsstore_new: "_ns, aError)); } - case 43: { // tabs:uniffi_tabs_fn_method_tabsstore_bridged_engine + case 35: { // tabs:uniffi_tabs_fn_method_tabsstore_bridged_engine using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsstore_bridged_engine, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsstore_bridged_engine: "_ns, aError)); } - case 44: { // tabs:uniffi_tabs_fn_method_tabsstore_get_all + case 36: { // tabs:uniffi_tabs_fn_method_tabsstore_get_all using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsstore_get_all, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsstore_get_all: "_ns, aError)); } - case 45: { // tabs:uniffi_tabs_fn_method_tabsstore_register_with_sync_manager + case 37: { // tabs:uniffi_tabs_fn_method_tabsstore_register_with_sync_manager using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsstore_register_with_sync_manager, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsstore_register_with_sync_manager: "_ns, aError)); } - case 46: { // tabs:uniffi_tabs_fn_method_tabsstore_set_local_tabs + case 38: { // tabs:uniffi_tabs_fn_method_tabsstore_set_local_tabs using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>, ScaffoldingConverter>; return Some(CallHandler::CallAsync(uniffi_tabs_fn_method_tabsstore_set_local_tabs, aGlobal, aArgs, "uniffi_tabs_fn_method_tabsstore_set_local_tabs: "_ns, aError)); } @@ -318,237 +272,197 @@ Maybe> UniFFICallAsync(const GlobalObject& aGlobal, ui bool UniFFICallSync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, RootedDictionary& aReturnValue, ErrorResult& aError) { switch (aId) { - case 0: { // relevancy:uniffi_relevancy_fn_clone_relevancystore - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRelevancyRelevancyStorePointerType>>; - CallHandler::CallSync(uniffi_relevancy_fn_clone_relevancystore, aGlobal, aArgs, aReturnValue, "uniffi_relevancy_fn_clone_relevancystore: "_ns, aError); - return true; - } - case 1: { // relevancy:uniffi_relevancy_fn_constructor_relevancystore_new + case 0: { // relevancy:uniffi_relevancy_fn_constructor_relevancystore_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_relevancy_fn_constructor_relevancystore_new, aGlobal, aArgs, aReturnValue, "uniffi_relevancy_fn_constructor_relevancystore_new: "_ns, aError); return true; } - case 2: { // relevancy:uniffi_relevancy_fn_method_relevancystore_calculate_metrics + case 1: { // relevancy:uniffi_relevancy_fn_method_relevancystore_calculate_metrics using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRelevancyRelevancyStorePointerType>>; CallHandler::CallSync(uniffi_relevancy_fn_method_relevancystore_calculate_metrics, aGlobal, aArgs, aReturnValue, "uniffi_relevancy_fn_method_relevancystore_calculate_metrics: "_ns, aError); return true; } - case 3: { // relevancy:uniffi_relevancy_fn_method_relevancystore_ingest + case 2: { // relevancy:uniffi_relevancy_fn_method_relevancystore_ingest using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRelevancyRelevancyStorePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_relevancy_fn_method_relevancystore_ingest, aGlobal, aArgs, aReturnValue, "uniffi_relevancy_fn_method_relevancystore_ingest: "_ns, aError); return true; } - case 4: { // relevancy:uniffi_relevancy_fn_method_relevancystore_user_interest_vector + case 3: { // relevancy:uniffi_relevancy_fn_method_relevancystore_user_interest_vector using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRelevancyRelevancyStorePointerType>>; CallHandler::CallSync(uniffi_relevancy_fn_method_relevancystore_user_interest_vector, aGlobal, aArgs, aReturnValue, "uniffi_relevancy_fn_method_relevancystore_user_interest_vector: "_ns, aError); return true; } - case 5: { // remote_settings:uniffi_remote_settings_fn_clone_remotesettings - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRemoteSettingsRemoteSettingsPointerType>>; - CallHandler::CallSync(uniffi_remote_settings_fn_clone_remotesettings, aGlobal, aArgs, aReturnValue, "uniffi_remote_settings_fn_clone_remotesettings: "_ns, aError); - return true; - } - case 6: { // remote_settings:uniffi_remote_settings_fn_constructor_remotesettings_new + case 4: { // remote_settings:uniffi_remote_settings_fn_constructor_remotesettings_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_remote_settings_fn_constructor_remotesettings_new, aGlobal, aArgs, aReturnValue, "uniffi_remote_settings_fn_constructor_remotesettings_new: "_ns, aError); return true; } - case 7: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path + case 5: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRemoteSettingsRemoteSettingsPointerType>, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path, aGlobal, aArgs, aReturnValue, "uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path: "_ns, aError); return true; } - case 8: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records + case 6: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRemoteSettingsRemoteSettingsPointerType>>; CallHandler::CallSync(uniffi_remote_settings_fn_method_remotesettings_get_records, aGlobal, aArgs, aReturnValue, "uniffi_remote_settings_fn_method_remotesettings_get_records: "_ns, aError); return true; } - case 9: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records_since + case 7: { // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records_since using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRemoteSettingsRemoteSettingsPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_remote_settings_fn_method_remotesettings_get_records_since, aGlobal, aArgs, aReturnValue, "uniffi_remote_settings_fn_method_remotesettings_get_records_since: "_ns, aError); return true; } - case 10: { // suggest:uniffi_suggest_fn_clone_suggeststore - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; - CallHandler::CallSync(uniffi_suggest_fn_clone_suggeststore, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_clone_suggeststore: "_ns, aError); - return true; - } - case 11: { // suggest:uniffi_suggest_fn_constructor_suggeststore_new + case 8: { // suggest:uniffi_suggest_fn_constructor_suggeststore_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_suggest_fn_constructor_suggeststore_new, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_constructor_suggeststore_new: "_ns, aError); return true; } - case 12: { // suggest:uniffi_suggest_fn_method_suggeststore_clear + case 9: { // suggest:uniffi_suggest_fn_method_suggeststore_clear using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststore_clear, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststore_clear: "_ns, aError); return true; } - case 13: { // suggest:uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; - CallHandler::CallSync(uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststore_clear_dismissed_suggestions: "_ns, aError); - return true; - } - case 14: { // suggest:uniffi_suggest_fn_method_suggeststore_dismiss_suggestion - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>, ScaffoldingConverter>; - CallHandler::CallSync(uniffi_suggest_fn_method_suggeststore_dismiss_suggestion, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststore_dismiss_suggestion: "_ns, aError); - return true; - } - case 15: { // suggest:uniffi_suggest_fn_method_suggeststore_fetch_global_config + case 10: { // suggest:uniffi_suggest_fn_method_suggeststore_fetch_global_config using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststore_fetch_global_config, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststore_fetch_global_config: "_ns, aError); return true; } - case 16: { // suggest:uniffi_suggest_fn_method_suggeststore_fetch_provider_config + case 11: { // suggest:uniffi_suggest_fn_method_suggeststore_fetch_provider_config using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststore_fetch_provider_config, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststore_fetch_provider_config: "_ns, aError); return true; } - case 17: { // suggest:uniffi_suggest_fn_method_suggeststore_ingest + case 12: { // suggest:uniffi_suggest_fn_method_suggeststore_ingest using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststore_ingest, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststore_ingest: "_ns, aError); return true; } - case 18: { // suggest:uniffi_suggest_fn_method_suggeststore_interrupt + case 13: { // suggest:uniffi_suggest_fn_method_suggeststore_interrupt using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststore_interrupt, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststore_interrupt: "_ns, aError); return true; } - case 19: { // suggest:uniffi_suggest_fn_method_suggeststore_query + case 14: { // suggest:uniffi_suggest_fn_method_suggeststore_query using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStorePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststore_query, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststore_query: "_ns, aError); return true; } - case 20: { // suggest:uniffi_suggest_fn_clone_suggeststorebuilder - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>>; - CallHandler::CallSync(uniffi_suggest_fn_clone_suggeststorebuilder, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_clone_suggeststorebuilder: "_ns, aError); - return true; - } - case 21: { // suggest:uniffi_suggest_fn_constructor_suggeststorebuilder_new + case 15: { // suggest:uniffi_suggest_fn_constructor_suggeststorebuilder_new using CallHandler = ScaffoldingCallHandler>; CallHandler::CallSync(uniffi_suggest_fn_constructor_suggeststorebuilder_new, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_constructor_suggeststorebuilder_new: "_ns, aError); return true; } - case 22: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_build + case 16: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_build using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststorebuilder_build, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststorebuilder_build: "_ns, aError); return true; } - case 23: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_cache_path + case 17: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_cache_path using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststorebuilder_cache_path, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststorebuilder_cache_path: "_ns, aError); return true; } - case 24: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_data_path + case 18: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_data_path using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststorebuilder_data_path, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststorebuilder_data_path: "_ns, aError); return true; } - case 25: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config + case 19: { // suggest:uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSuggestSuggestStoreBuilderPointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config: "_ns, aError); return true; } - case 26: { // suggest:uniffi_suggest_fn_func_raw_suggestion_url_matches + case 20: { // suggest:uniffi_suggest_fn_func_raw_suggestion_url_matches using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_suggest_fn_func_raw_suggestion_url_matches, aGlobal, aArgs, aReturnValue, "uniffi_suggest_fn_func_raw_suggestion_url_matches: "_ns, aError); return true; } - case 27: { // tabs:uniffi_tabs_fn_clone_tabsbridgedengine - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; - CallHandler::CallSync(uniffi_tabs_fn_clone_tabsbridgedengine, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_clone_tabsbridgedengine: "_ns, aError); - return true; - } - case 28: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_apply + case 21: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_apply using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_apply, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_apply: "_ns, aError); return true; } - case 29: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id + case 22: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_ensure_current_sync_id: "_ns, aError); return true; } - case 30: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_last_sync + case 23: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_last_sync using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_last_sync, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_last_sync: "_ns, aError); return true; } - case 31: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync + case 24: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_prepare_for_sync: "_ns, aError); return true; } - case 32: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset + case 25: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_reset, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_reset: "_ns, aError); return true; } - case 33: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id + case 26: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id: "_ns, aError); return true; } - case 34: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync + case 27: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_set_last_sync: "_ns, aError); return true; } - case 35: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded + case 28: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter, ScaffoldingConverter>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_set_uploaded: "_ns, aError); return true; } - case 36: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_store_incoming + case 29: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_store_incoming using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_store_incoming, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_store_incoming: "_ns, aError); return true; } - case 37: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_finished + case 30: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_finished using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_sync_finished, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_sync_finished: "_ns, aError); return true; } - case 38: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_id + case 31: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_id using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_sync_id, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_sync_id: "_ns, aError); return true; } - case 39: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_started + case 32: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_started using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_sync_started, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_sync_started: "_ns, aError); return true; } - case 40: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_wipe + case 33: { // tabs:uniffi_tabs_fn_method_tabsbridgedengine_wipe using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsBridgedEnginePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsbridgedengine_wipe, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsbridgedengine_wipe: "_ns, aError); return true; } - case 41: { // tabs:uniffi_tabs_fn_clone_tabsstore - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>>; - CallHandler::CallSync(uniffi_tabs_fn_clone_tabsstore, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_clone_tabsstore: "_ns, aError); - return true; - } - case 42: { // tabs:uniffi_tabs_fn_constructor_tabsstore_new + case 34: { // tabs:uniffi_tabs_fn_constructor_tabsstore_new using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; CallHandler::CallSync(uniffi_tabs_fn_constructor_tabsstore_new, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_constructor_tabsstore_new: "_ns, aError); return true; } - case 43: { // tabs:uniffi_tabs_fn_method_tabsstore_bridged_engine + case 35: { // tabs:uniffi_tabs_fn_method_tabsstore_bridged_engine using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsstore_bridged_engine, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsstore_bridged_engine: "_ns, aError); return true; } - case 44: { // tabs:uniffi_tabs_fn_method_tabsstore_get_all + case 36: { // tabs:uniffi_tabs_fn_method_tabsstore_get_all using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsstore_get_all, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsstore_get_all: "_ns, aError); return true; } - case 45: { // tabs:uniffi_tabs_fn_method_tabsstore_register_with_sync_manager + case 37: { // tabs:uniffi_tabs_fn_method_tabsstore_register_with_sync_manager using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsstore_register_with_sync_manager, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsstore_register_with_sync_manager: "_ns, aError); return true; } - case 46: { // tabs:uniffi_tabs_fn_method_tabsstore_set_local_tabs + case 38: { // tabs:uniffi_tabs_fn_method_tabsstore_set_local_tabs using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTabsTabsStorePointerType>, ScaffoldingConverter>; CallHandler::CallSync(uniffi_tabs_fn_method_tabsstore_set_local_tabs, aGlobal, aArgs, aReturnValue, "uniffi_tabs_fn_method_tabsstore_set_local_tabs: "_ns, aError); return true; diff --git a/toolkit/components/uniffi-js/UniFFIPointer.cpp b/toolkit/components/uniffi-js/UniFFIPointer.cpp index 417da1985d35..c3a1eba93dc0 100644 --- a/toolkit/components/uniffi-js/UniFFIPointer.cpp +++ b/toolkit/components/uniffi-js/UniFFIPointer.cpp @@ -110,15 +110,6 @@ bool UniFFIPointer::IsSamePtrType(const UniFFIPointerType* aType) const { return this->mType == aType; } -UniFFIPointer* UniFFIPointer::Clone() { - MOZ_LOG(sUniFFIPointerLogger, LogLevel::Info, ("[UniFFI] cloning pointer")); - RustCallStatus status{}; - auto cloned = this->mType->clone(this->mPtr, &status); - MOZ_DIAGNOSTIC_ASSERT(status.code == RUST_CALL_SUCCESS, - "UniFFI clone call returned a non-success result"); - return new UniFFIPointer(cloned, this->mType); -} - UniFFIPointer::~UniFFIPointer() { MOZ_LOG(sUniFFIPointerLogger, LogLevel::Info, ("[UniFFI] Destroying pointer")); diff --git a/toolkit/components/uniffi-js/UniFFIPointer.h b/toolkit/components/uniffi-js/UniFFIPointer.h index 87d5832eea17..59acc0ca666c 100644 --- a/toolkit/components/uniffi-js/UniFFIPointer.h +++ b/toolkit/components/uniffi-js/UniFFIPointer.h @@ -35,8 +35,6 @@ class UniFFIPointer final : public nsISupports, public nsWrapperCache { JS::Handle aGivenProto) override; nsISupports* GetParentObject() { return nullptr; } - UniFFIPointer* Clone(); - /** * returns the raw pointer `UniFFIPointer` holds * This is safe because: diff --git a/toolkit/components/uniffi-js/UniFFIPointerType.h b/toolkit/components/uniffi-js/UniFFIPointerType.h index 25294cfc9de1..7236e50cb79c 100644 --- a/toolkit/components/uniffi-js/UniFFIPointerType.h +++ b/toolkit/components/uniffi-js/UniFFIPointerType.h @@ -21,9 +21,7 @@ namespace mozilla::uniffi { **/ struct UniFFIPointerType { nsLiteralCString typeName; - // Rust FFI function to clone for the pointer - void* (*clone)(void*, RustCallStatus*); - // Rust FFI function to destroy for the pointer + // The Rust destructor for the pointer, this gives back ownership to Rust void (*destructor)(void*, RustCallStatus*); }; } // namespace mozilla::uniffi diff --git a/toolkit/components/uniffi-js/UniFFIRust.h b/toolkit/components/uniffi-js/UniFFIRust.h index 608b8063aeff..2907af8f51a1 100644 --- a/toolkit/components/uniffi-js/UniFFIRust.h +++ b/toolkit/components/uniffi-js/UniFFIRust.h @@ -28,8 +28,8 @@ constexpr int8_t CALLBACK_INTERFACE_UNEXPECTED_ERROR = 2; // structs/functions from UniFFI extern "C" { struct RustBuffer { - uint64_t capacity; - uint64_t len; + int32_t capacity; + int32_t len; uint8_t* data; }; @@ -42,7 +42,7 @@ typedef int (*ForeignCallback)(uint64_t handle, uint32_t method, const uint8_t* argsData, int32_t argsLen, RustBuffer* buf_ptr); -RustBuffer uniffi_rustbuffer_alloc(uint64_t size, RustCallStatus* call_status); +RustBuffer uniffi_rustbuffer_alloc(int32_t size, RustCallStatus* call_status); void uniffi_rustbuffer_free(RustBuffer buf, RustCallStatus* call_status); } diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml index a084247ecfa7..a542f707a144 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -72,18 +72,18 @@ origin-trials-ffi = { path = "../../../../dom/origin-trials/ffi" } jog = { path = "../../../components/glean/bindings/jog" } dap_ffi = { path = "../../../components/telemetry/dap/ffi" } data-encoding-ffi = { path = "../../../../dom/fs/parent/rust/data-encoding-ffi" } -uniffi-example-arithmetic = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } -uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } -uniffi-example-rondpoint = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } -uniffi-example-sprites = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } -uniffi-example-todolist = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } +uniffi-example-arithmetic = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } +uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } +uniffi-example-rondpoint = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } +uniffi-example-sprites = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } +uniffi-example-todolist = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } uniffi-example-custom-types = { path = "../../../components/uniffi-example-custom-types/", optional = true } uniffi-fixture-callbacks = { path = "../../../components/uniffi-fixture-callbacks/", optional = true } uniffi-fixture-external-types = { path = "../../../components/uniffi-fixture-external-types/", optional = true } binary_http = { path = "../../../../netwerk/protocol/http/binary_http" } oblivious_http = { path = "../../../../netwerk/protocol/http/oblivious_http" } mime-guess-ffi = { path = "../../../../dom/fs/parent/rust/mime-guess-ffi" } -uniffi = { workspace = true } +uniffi = { version = "0.25.2" } # Note: `modern_sqlite` means rusqlite's bindings file be for a sqlite with # version less than or equal to what we link to. This isn't a problem because we diff --git a/toolkit/library/rust/shared/lib.rs b/toolkit/library/rust/shared/lib.rs index dd1bfc7c5e41..a6dfe60411f9 100644 --- a/toolkit/library/rust/shared/lib.rs +++ b/toolkit/library/rust/shared/lib.rs @@ -174,7 +174,7 @@ pub unsafe extern "C" fn debug_log(target: *const c_char, message: *const c_char // Define extern "C" versions of these UniFFI functions, so that they can be called from C++ #[no_mangle] pub extern "C" fn uniffi_rustbuffer_alloc( - size: u64, + size: i32, call_status: &mut uniffi::RustCallStatus, ) -> uniffi::RustBuffer { uniffi::uniffi_rustbuffer_alloc(size, call_status) diff --git a/tools/lint/trojan-source.yml b/tools/lint/trojan-source.yml index a273626b588b..611ab660f505 100644 --- a/tools/lint/trojan-source.yml +++ b/tools/lint/trojan-source.yml @@ -14,7 +14,6 @@ trojan-source: - third_party/python/arrow/arrow/locales.py - third_party/rust/chardetng/src/data.rs - third_party/rust/clap_builder/src/output/textwrap/core.rs - - third_party/rust/textwrap/src/core.rs - third_party/rust/icu_provider/src/hello_world.rs - third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py - third_party/rust/error-chain/tests/tests.rs -- 2.11.4.GIT