From a5e425682bae26132fcbb705aea8e3dc10d55329 Mon Sep 17 00:00:00 2001 From: Cristian Tuns Date: Tue, 9 Apr 2024 21:54:42 -0400 Subject: [PATCH] Backed out 2 changesets (bug 1888683) for causing hazard bustages in UniFFIPointer.cpp CLOSED TREE Backed out changeset 42fe954d2d47 (bug 1888683) Backed out changeset 2403582c3c8d (bug 1888683) --- .cargo/config.toml.in | 8 +- Cargo.lock | 157 ++-- Cargo.toml | 35 +- build/rust/goblin/Cargo.toml | 19 +- build/rust/scroll/Cargo.toml | 17 - build/rust/scroll/lib.rs | 11 - dom/chrome-webidl/UniFFI.webidl | 2 +- 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/DependenciesPlugin.kt | 2 +- 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 +- .../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 +- .../rust/glean-core/src/database/mod.rs | 1 + third_party/rust/glean-core/src/debug.rs | 1 + .../rust/glean-core/src/dispatcher/mod.rs | 5 +- .../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 - .../rust/glean-core/src/histogram/mod.rs | 1 + .../rust/glean-core/src/internal_pings.rs | 11 +- third_party/rust/glean-core/src/lib.rs | 5 +- .../rust/glean-core/src/lib_unit_tests.rs | 82 +- .../rust/glean-core/src/metrics/event.rs | 16 +- .../glean-core/src/metrics/memory_unit.rs | 2 + .../src/metrics/metrics_enabled_config.rs | 2 +- .../rust/glean-core/src/metrics/ping.rs | 31 - .../rust/glean-core/src/metrics/string.rs | 2 + .../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 + .../src/metrics/timing_distribution.rs | 2 +- .../rust/glean-core/src/metrics/url.rs | 2 + .../rust/glean-core/src/storage/mod.rs | 4 +- .../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 + .../rust/glean-core/src/upload/request.rs | 2 +- .../rust/glean-core/tests/common/mod.rs | 1 - third_party/rust/glean-core/tests/event.rs | 1 - .../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 +- .../rust/goblin/src/mach/load_command.rs | 3 - .../rust/goblin/src/pe/authenticode.rs | 200 +---- .../rust/goblin/src/pe/certificate_table.rs | 28 +- .../rust/goblin/src/pe/data_directories.rs | 175 ++--- third_party/rust/goblin/src/pe/header.rs | 150 +--- third_party/rust/goblin/src/pe/mod.rs | 249 +----- .../rust/goblin/src/pe/optional_header.rs | 83 -- third_party/rust/goblin/src/pe/options.rs | 10 +- .../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 -- .../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 +- .../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 -- .../rust/smawk/tests/random_monge/mod.rs | 83 -- .../rust/smawk/tests/version-numbers.rs | 9 - third_party/rust/suggest/.cargo-checksum.json | 2 +- third_party/rust/suggest/Cargo.toml | 28 +- .../rust/suggest/benches/benchmark_all.rs | 25 - .../rust/suggest/src/benchmarks/README.md | 28 - .../rust/suggest/src/benchmarks/client.rs | 97 --- .../rust/suggest/src/benchmarks/ingest.rs | 116 --- .../rust/suggest/src/benchmarks/mod.rs | 40 - .../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 +- .../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 -- .../rust/textwrap/src/word_separators.rs | 481 ------------ .../rust/textwrap/src/word_splitters.rs | 314 -------- third_party/rust/textwrap/src/wrap.rs | 686 ---------------- .../rust/textwrap/src/wrap_algorithms.rs | 413 ---------- .../src/wrap_algorithms/optimal_fit.rs | 433 ----------- third_party/rust/textwrap/tests/indent.rs | 88 --- .../rust/textwrap/tests/version-numbers.rs | 22 - .../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 ---- .../rust/unicode-linebreak/src/shared.rs | 134 ---- .../rust/unicode-linebreak/src/tables.rs | 10 - .../.cargo-checksum.json | 2 +- .../rust/uniffi-example-arithmetic/Cargo.toml | 6 +- .../.cargo-checksum.json | 2 +- .../rust/uniffi-example-geometry/Cargo.toml | 6 +- .../tests/bindings/test_geometry.py | 6 +- .../tests/bindings/test_geometry.rb | 6 +- .../.cargo-checksum.json | 2 +- .../rust/uniffi-example-rondpoint/Cargo.toml | 6 +- .../tests/bindings/test_rondpoint.py | 2 +- .../tests/bindings/test_rondpoint.rb | 7 +- .../.cargo-checksum.json | 2 +- .../rust/uniffi-example-sprites/Cargo.toml | 6 +- .../tests/bindings/test_sprites.py | 18 +- .../tests/bindings/test_sprites.rb | 18 +- .../.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 -- .../uniffi_bindgen/src/backend/filters.rs | 4 +- .../kotlin/gen_kotlin/callback_interface.rs | 2 +- .../bindings/kotlin/gen_kotlin/compounds.rs | 115 +-- .../bindings/kotlin/gen_kotlin/executor.rs | 24 + .../bindings/kotlin/gen_kotlin/external.rs | 4 +- .../src/bindings/kotlin/gen_kotlin/mod.rs | 251 +----- .../src/bindings/kotlin/gen_kotlin/object.rs | 19 +- .../bindings/kotlin/gen_kotlin/primitives.rs | 10 +- .../src/bindings/kotlin/templates/Async.kt | 107 +-- .../kotlin/templates/BooleanHelper.kt | 2 +- .../kotlin/templates/ByteArrayHelper.kt | 4 +- .../kotlin/templates/CallbackInterfaceImpl.kt | 117 --- .../templates/CallbackInterfaceRuntime.kt | 65 +- .../templates/CallbackInterfaceTemplate.kt | 140 +++- .../kotlin/templates/CustomTypeTemplate.kt | 2 +- .../kotlin/templates/DurationHelper.kt | 2 +- .../bindings/kotlin/templates/EnumTemplate.kt | 30 +- .../kotlin/templates/ErrorTemplate.kt | 18 +- .../kotlin/templates/ExternalTypeTemplate.kt | 2 +- .../kotlin/templates/FfiConverterTemplate.kt | 6 +- .../kotlin/templates/Float32Helper.kt | 2 +- .../kotlin/templates/Float64Helper.kt | 2 +- .../templates/ForeignExecutorTemplate.kt | 83 ++ .../bindings/kotlin/templates/HandleMap.kt | 27 - .../src/bindings/kotlin/templates/Helpers.kt | 152 ++-- .../bindings/kotlin/templates/Int16Helper.kt | 2 +- .../bindings/kotlin/templates/Int32Helper.kt | 2 +- .../bindings/kotlin/templates/Int64Helper.kt | 2 +- .../bindings/kotlin/templates/Int8Helper.kt | 2 +- .../bindings/kotlin/templates/Interface.kt | 14 - .../bindings/kotlin/templates/MapTemplate.kt | 4 +- .../templates/NamespaceLibraryTemplate.kt | 61 +- .../kotlin/templates/ObjectCleanerHelper.kt | 40 - .../templates/ObjectCleanerHelperAndroid.kt | 26 - .../templates/ObjectCleanerHelperJvm.kt | 25 - .../kotlin/templates/ObjectRuntime.kt | 161 ++++ .../kotlin/templates/ObjectTemplate.kt | 343 +++----- .../kotlin/templates/OptionalTemplate.kt | 6 +- .../src/bindings/kotlin/templates/README.md | 13 - .../kotlin/templates/RecordTemplate.kt | 29 +- .../kotlin/templates/RustBufferTemplate.kt | 39 +- .../kotlin/templates/SequenceTemplate.kt | 6 +- .../bindings/kotlin/templates/StringHelper.kt | 10 +- .../kotlin/templates/TimestampHelper.kt | 2 +- .../templates/TopLevelFunctionTemplate.kt | 52 +- .../src/bindings/kotlin/templates/Types.kt | 40 +- .../bindings/kotlin/templates/UInt16Helper.kt | 2 +- .../bindings/kotlin/templates/UInt32Helper.kt | 2 +- .../bindings/kotlin/templates/UInt64Helper.kt | 2 +- .../bindings/kotlin/templates/UInt8Helper.kt | 2 +- .../src/bindings/kotlin/templates/macros.kt | 140 +--- .../src/bindings/kotlin/templates/wrapper.kt | 4 - .../src/bindings/kotlin/test.rs | 16 +- .../bindings/python/gen_python/compounds.rs | 16 +- .../bindings/python/gen_python/executor.rs | 18 + .../bindings/python/gen_python/external.rs | 2 +- .../src/bindings/python/gen_python/mod.rs | 177 +---- .../src/bindings/python/templates/Async.py | 86 +- .../python/templates/BooleanHelper.py | 18 +- .../bindings/python/templates/BytesHelper.py | 5 +- .../python/templates/CallbackInterfaceImpl.py | 98 --- .../templates/CallbackInterfaceRuntime.py | 59 +- .../templates/CallbackInterfaceTemplate.py | 112 ++- .../bindings/python/templates/CustomType.py | 9 - .../python/templates/DurationHelper.py | 8 +- .../bindings/python/templates/EnumTemplate.py | 71 +- .../python/templates/ErrorTemplate.py | 19 - .../python/templates/ExternalTemplate.py | 8 +- .../python/templates/Float32Helper.py | 2 +- .../python/templates/Float64Helper.py | 2 +- .../templates/ForeignExecutorTemplate.py | 63 ++ .../bindings/python/templates/HandleMap.py | 33 - .../src/bindings/python/templates/Helpers.py | 36 +- .../bindings/python/templates/Int16Helper.py | 2 +- .../bindings/python/templates/Int32Helper.py | 2 +- .../bindings/python/templates/Int64Helper.py | 2 +- .../bindings/python/templates/Int8Helper.py | 2 +- .../bindings/python/templates/MapTemplate.py | 6 - .../templates/NamespaceLibraryTemplate.py | 45 +- .../python/templates/ObjectTemplate.py | 124 +-- .../python/templates/OptionalTemplate.py | 5 - .../python/templates/PointerManager.py | 68 ++ .../src/bindings/python/templates/Protocol.py | 9 - .../python/templates/RecordTemplate.py | 24 +- .../python/templates/RustBufferHelper.py | 18 +- .../python/templates/RustBufferTemplate.py | 11 +- .../python/templates/SequenceTemplate.py | 5 - .../bindings/python/templates/StringHelper.py | 4 +- .../python/templates/TimestampHelper.py | 4 - .../templates/TopLevelFunctionTemplate.py | 24 +- .../src/bindings/python/templates/Types.py | 5 +- .../bindings/python/templates/UInt16Helper.py | 2 +- .../bindings/python/templates/UInt32Helper.py | 2 +- .../bindings/python/templates/UInt64Helper.py | 2 +- .../bindings/python/templates/UInt8Helper.py | 2 +- .../src/bindings/python/templates/macros.py | 95 +-- .../src/bindings/python/templates/wrapper.py | 17 +- .../src/bindings/python/test.rs | 14 +- .../src/bindings/ruby/gen_ruby/mod.rs | 79 +- .../bindings/ruby/templates/ObjectTemplate.rb | 36 +- .../bindings/ruby/templates/RecordTemplate.rb | 7 +- .../ruby/templates/RustBufferBuilder.rb | 2 +- .../ruby/templates/RustBufferStream.rb | 4 +- .../ruby/templates/RustBufferTemplate.rb | 42 +- .../templates/TopLevelFunctionTemplate.rb | 4 +- .../src/bindings/ruby/templates/macros.rb | 10 +- .../uniffi_bindgen/src/bindings/ruby/test.rs | 15 +- .../swift/gen_swift/callback_interface.rs | 12 +- .../src/bindings/swift/gen_swift/compounds.rs | 5 +- .../src/bindings/swift/gen_swift/executor.rs | 23 + .../src/bindings/swift/gen_swift/external.rs | 2 +- .../src/bindings/swift/gen_swift/mod.rs | 209 +---- .../src/bindings/swift/gen_swift/object.rs | 18 +- .../bindings/swift/gen_swift/primitives.rs | 8 +- .../src/bindings/swift/templates/Async.swift | 100 +-- .../swift/templates/BridgingHeaderTemplate.h | 48 +- .../templates/CallbackInterfaceImpl.swift | 113 --- .../templates/CallbackInterfaceRuntime.swift | 57 ++ .../templates/CallbackInterfaceTemplate.swift | 145 +++- .../swift/templates/EnumTemplate.swift | 27 +- .../swift/templates/ErrorTemplate.swift | 12 +- .../templates/ForeignExecutorTemplate.swift | 69 ++ .../bindings/swift/templates/HandleMap.swift | 40 - .../bindings/swift/templates/Helpers.swift | 44 +- .../swift/templates/ObjectTemplate.swift | 201 ++--- .../bindings/swift/templates/Protocol.swift | 12 - .../swift/templates/RecordTemplate.swift | 17 +- .../swift/templates/RustBufferTemplate.swift | 4 - .../templates/TopLevelFunctionTemplate.swift | 49 +- .../src/bindings/swift/templates/Types.swift | 3 + .../src/bindings/swift/templates/macros.swift | 125 +-- .../bindings/swift/templates/wrapper.swift | 8 - .../uniffi_bindgen/src/bindings/swift/test.rs | 24 +- .../uniffi_bindgen/src/interface/callbacks.rs | 207 +---- .../uniffi_bindgen/src/interface/enum_.rs | 224 +----- .../rust/uniffi_bindgen/src/interface/ffi.rs | 195 +---- .../uniffi_bindgen/src/interface/function.rs | 32 - .../rust/uniffi_bindgen/src/interface/mod.rs | 342 +++----- .../uniffi_bindgen/src/interface/object.rs | 199 +---- .../uniffi_bindgen/src/interface/record.rs | 53 -- .../uniffi_bindgen/src/interface/universe.rs | 5 +- third_party/rust/uniffi_bindgen/src/lib.rs | 138 +--- .../rust/uniffi_bindgen/src/library_mode.rs | 40 +- .../uniffi_bindgen/src/macro_metadata/ci.rs | 21 +- .../src/macro_metadata/extract.rs | 2 +- .../uniffi_bindgen/src/scaffolding/mod.rs | 36 +- .../templates/CallbackInterfaceTemplate.rs | 93 ++- .../src/scaffolding/templates/EnumTemplate.rs | 13 +- .../scaffolding/templates/ErrorTemplate.rs | 10 +- .../templates/ExternalTypesTemplate.rs | 2 - .../scaffolding/templates/ObjectTemplate.rs | 34 +- .../scaffolding/templates/RecordTemplate.rs | 8 +- .../templates/TopLevelFunctionTemplate.rs | 5 +- .../rust/uniffi_build/.cargo-checksum.json | 2 +- third_party/rust/uniffi_build/Cargo.toml | 5 +- third_party/rust/uniffi_build/README.md | 81 -- .../.cargo-checksum.json | 2 +- .../rust/uniffi_checksum_derive/Cargo.toml | 3 +- .../rust/uniffi_checksum_derive/README.md | 81 -- .../rust/uniffi_core/.cargo-checksum.json | 2 +- third_party/rust/uniffi_core/Cargo.toml | 6 +- third_party/rust/uniffi_core/README.md | 81 -- .../uniffi_core/src/ffi/callbackinterface.rs | 125 ++- .../rust/uniffi_core/src/ffi/ffidefault.rs | 11 +- .../uniffi_core/src/ffi/foreigncallbacks.rs | 116 ++- .../uniffi_core/src/ffi/foreignexecutor.rs | 487 ++++++++++++ .../rust/uniffi_core/src/ffi/foreignfuture.rs | 241 ------ .../rust/uniffi_core/src/ffi/handle.rs | 46 -- third_party/rust/uniffi_core/src/ffi/mod.rs | 6 +- .../rust/uniffi_core/src/ffi/rustbuffer.rs | 122 ++- .../rust/uniffi_core/src/ffi/rustcalls.rs | 9 +- .../rust/uniffi_core/src/ffi/rustfuture.rs | 735 ++++++++++++++++++ .../uniffi_core/src/ffi/rustfuture/future.rs | 320 -------- .../uniffi_core/src/ffi/rustfuture/mod.rs | 141 ---- .../src/ffi/rustfuture/scheduler.rs | 96 --- .../uniffi_core/src/ffi/rustfuture/tests.rs | 223 ------ .../uniffi_core/src/ffi_converter_impls.rs | 75 +- .../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 | 308 ++------ third_party/rust/uniffi_macros/src/error.rs | 101 +-- third_party/rust/uniffi_macros/src/export.rs | 211 +++-- .../uniffi_macros/src/export/attributes.rs | 306 +------- .../src/export/callback_interface.rs | 204 ++--- .../rust/uniffi_macros/src/export/item.rs | 88 +-- .../uniffi_macros/src/export/scaffolding.rs | 123 ++- .../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 ++- .../uniffi_macros/src/setup_scaffolding.rs | 57 +- third_party/rust/uniffi_macros/src/util.rs | 47 +- .../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 +- .../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 +- .../uniffi_udl/src/converters/callables.rs | 16 +- .../rust/uniffi_udl/src/converters/enum_.rs | 79 +- .../uniffi_udl/src/converters/interface.rs | 6 +- .../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 +- .../components/glean/api/src/common_test.rs | 1 - toolkit/components/glean/src/init/mod.rs | 1 - .../uniffi-bindgen-gecko-js/Cargo.toml | 2 +- .../generated/RustRelevancy.sys.mjs | 8 +- .../generated/RustRemoteSettings.sys.mjs | 8 +- .../components/generated/RustSuggest.sys.mjs | 67 +- .../components/generated/RustTabs.sys.mjs | 36 +- .../uniffi-bindgen-gecko-js/config.toml | 27 +- .../fixtures/generated/RustArithmetic.sys.mjs | 8 +- .../generated/RustCustomTypes.sys.mjs | 2 +- .../generated/RustExternalTypes.sys.mjs | 4 +- .../fixtures/generated/RustGeometry.sys.mjs | 4 +- .../fixtures/generated/RustRefcounts.sys.mjs | 388 --------- .../fixtures/generated/RustRondpoint.sys.mjs | 132 ++-- .../fixtures/generated/RustSprites.sys.mjs | 16 +- .../fixtures/generated/RustTodolist.sys.mjs | 34 +- .../fixtures/moz.build | 1 - .../fixtures/tests/xpcshell/test_refcounts.js | 57 -- .../fixtures/tests/xpcshell/xpcshell.toml | 15 - .../uniffi-bindgen-gecko-js/src/render/cpp.rs | 40 +- .../uniffi-bindgen-gecko-js/src/render/js.rs | 4 +- .../src/templates/UniFFIScaffolding.cpp | 3 +- .../uniffi-fixture-external-types/Cargo.toml | 2 +- .../uniffi-fixture-refcounts/Cargo.toml | 12 - .../uniffi-fixture-refcounts/build.rs | 7 - .../uniffi-fixture-refcounts/src/lib.rs | 28 - .../src/refcounts.udl | 8 - .../components/uniffi-js/OwnedRustBuffer.cpp | 4 +- .../uniffi-js/ScaffoldingConverter.h | 2 +- .../uniffi-js/UniFFIFixtureScaffolding.cpp | 527 ++++++------- .../uniffi-js/UniFFIGeneratedScaffolding.cpp | 254 ++---- .../components/uniffi-js/UniFFIPointer.cpp | 12 +- toolkit/components/uniffi-js/UniFFIPointer.h | 14 +- .../components/uniffi-js/UniFFIPointerType.h | 4 +- toolkit/components/uniffi-js/UniFFIRust.h | 6 +- toolkit/library/rust/shared/Cargo.toml | 15 +- toolkit/library/rust/shared/lib.rs | 3 +- tools/lint/trojan-source.yml | 1 - 469 files changed, 7065 insertions(+), 21234 deletions(-) delete mode 100644 build/rust/scroll/Cargo.toml delete mode 100644 build/rust/scroll/lib.rs delete mode 100644 third_party/rust/oneshot-uniffi/tests/raw.rs 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 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 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 delete mode 100644 third_party/rust/uniffi/README.md delete mode 100644 third_party/rust/uniffi_bindgen/README.md create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/executor.rs delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/CallbackInterfaceImpl.kt 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 delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/kotlin/templates/README.md create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/executor.rs delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/python/templates/CallbackInterfaceImpl.py 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 create mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs 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 delete mode 100644 third_party/rust/uniffi_bindgen/src/bindings/swift/templates/Protocol.swift delete mode 100644 third_party/rust/uniffi_build/README.md delete mode 100644 third_party/rust/uniffi_checksum_derive/README.md 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 delete mode 100644 third_party/rust/uniffi_macros/README.md delete mode 100644 third_party/rust/uniffi_macros/src/default.rs delete mode 100644 third_party/rust/uniffi_macros/src/export/trait_interface.rs delete mode 100644 third_party/rust/uniffi_meta/README.md delete mode 100644 third_party/rust/uniffi_udl/README.md delete mode 100644 toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRefcounts.sys.mjs delete mode 100644 toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_refcounts.js delete mode 100644 toolkit/components/uniffi-fixture-refcounts/Cargo.toml delete mode 100644 toolkit/components/uniffi-fixture-refcounts/build.rs delete mode 100644 toolkit/components/uniffi-fixture-refcounts/src/lib.rs delete mode 100644 toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl diff --git a/.cargo/config.toml.in b/.cargo/config.toml.in index c6bdc64ac1df1..3d10587cf1df4 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.4" 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 2523667fbed29..c3f3adf55c54f 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", @@ -2330,7 +2330,6 @@ dependencies = [ "uniffi-example-todolist", "uniffi-fixture-callbacks", "uniffi-fixture-external-types", - "uniffi-fixture-refcounts", "url", "viaduct", "webext_storage_bridge", @@ -2370,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", @@ -2383,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", @@ -2447,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]] @@ -2935,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", @@ -3619,7 +3618,7 @@ dependencies = [ "num-derive", "num-traits", "range-map", - "scroll 0.11.999", + "scroll", "smart-default", ] @@ -3633,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", @@ -3641,7 +3640,7 @@ dependencies = [ "minidump-common", "nix 0.27.1", "procfs-core", - "scroll 0.11.999", + "scroll", "tempfile", "thiserror", ] @@ -4131,7 +4130,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" @@ -4254,9 +4253,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" @@ -4575,7 +4574,7 @@ dependencies = [ name = "process_reader" version = "0.1.0" dependencies = [ - "goblin 0.7.999", + "goblin 0.7.1", "libc", "mach2", "memoffset 0.9.0", @@ -4816,7 +4815,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", @@ -4832,7 +4831,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", @@ -5057,25 +5056,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", @@ -5330,12 +5322,6 @@ dependencies = [ "syn", ] -[[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" @@ -5368,7 +5354,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", @@ -5549,7 +5535,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", @@ -5598,7 +5584,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", @@ -5609,7 +5595,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", @@ -5641,7 +5627,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", @@ -5686,17 +5672,6 @@ dependencies = [ 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" @@ -6012,12 +5987,6 @@ version = "1.0.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" @@ -6041,9 +6010,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", @@ -6070,7 +6039,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", @@ -6090,7 +6059,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", ] @@ -6098,7 +6067,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", ] @@ -6106,7 +6075,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", ] @@ -6114,7 +6083,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,18 +6107,11 @@ dependencies = [ "uniffi-example-geometry", ] -[[package]] -name = "uniffi-fixture-refcounts" -version = "0.21.0" -dependencies = [ - "uniffi", -] - [[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", @@ -6157,12 +6119,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", @@ -6171,9 +6132,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", @@ -6182,9 +6143,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", @@ -6192,9 +6153,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", @@ -6208,9 +6169,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", @@ -6221,14 +6182,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", @@ -6238,9 +6200,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", @@ -6251,12 +6213,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", @@ -6318,7 +6279,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", @@ -6466,7 +6427,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", @@ -6616,9 +6577,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 441e8c66b15e6..7b26009e165de 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 index 4b6ea811e97e6..52e8dfe66df1c 100644 --- a/build/rust/goblin/Cargo.toml +++ b/build/rust/goblin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "goblin" -version = "0.7.999" +version = "0.6.999" edition = "2018" license = "MIT/Apache-2.0" @@ -8,19 +8,4 @@ license = "MIT/Apache-2.0" 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"] +version = "0.7.0" diff --git a/build/rust/scroll/Cargo.toml b/build/rust/scroll/Cargo.toml deleted file mode 100644 index dea2c21fd1ace..0000000000000 --- 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 f7d352d6d2a86..0000000000000 --- 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 e24fc9cc5dc16..7a3f68fbbde5f 100644 --- a/dom/chrome-webidl/UniFFI.webidl +++ b/dom/chrome-webidl/UniFFI.webidl @@ -35,7 +35,7 @@ typedef unsigned long long UniFFICallbackObjectHandle; // Opaque type used to represent a pointer from Rust [ChromeOnly, Exposed=Window] -interface UniFFIPointer { }; +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 333aa68686bf4..2bf28a1b6e820 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]] @@ -2451,12 +2451,6 @@ dependencies = [ "serde", ] -[[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" @@ -2623,17 +2617,6 @@ version = "0.15.0" 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" @@ -2734,12 +2717,6 @@ version = "1.0.9" 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" @@ -2749,12 +2726,6 @@ dependencies = [ "tinyvec", ] -[[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" @@ -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 d548c5089f268..442c407fcaa76 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 b99404de0d28f..506226becafe1 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 93877277b5f3e..b06cd0f084066 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/DependenciesPlugin.kt b/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt index a58ac29588c16..6a3d4c212dfc3 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/python/sites/mach.txt b/python/sites/mach.txt index 90d6f153fc99e..e1cb8f159c066 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 b21bde4f1024e..0f9a2f75e977a 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 73065c6c4fc2f..5a47fcf5e5d13 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" @@ -692,30 +683,45 @@ user-id = 1 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 e81ad5191109d..475bff76658f1 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 074ad4a32d940..e4c39618a64a5 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 663b3141c3aef..54674fc7681a7 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 932b16a4a7c30..9d33444fbd569 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 9bda9bb462502..033cbe1472c37 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 f69f0c386878b..30f9a34f1166a 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 0dbf0220bcbb5..af473c98d956e 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 88f807bd88bbe..a572a02b8f72c 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 ead58fb86755c..48efa4ef96067 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 fa828242f1b4a..aaf850d019eec 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 50b2488a4c1c9..d83e56fbec9fb 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 dc71fea5941cd..e68a57ea4ce74 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 6e2880dffa32d..282b02e0ab590 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 1cf32feb604c2..07c3849006e5a 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 af68fde2648d2..b7f9d73beb95a 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 14d3b984172b2..cb1e4129d85fe 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 74f90f4867597..c7aefd9cd6437 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 19006a594e4ea..ce51b975fa17a 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 b36cbc150a6d3..26d0deff314cf 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 5defab7a71dc9..e60284b1e25fb 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 { @@ -72,26 +67,6 @@ impl PingType { precise_timestamps: bool, 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(), @@ -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 a56ffab6486c0..4aa30a8d7e064 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 35f803c72854c..baa8e88d7507d 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 6c68d5dff09ed..6d61a8a2429a8 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 d72492a5901a0..ee63fb52f8fab 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 776935afeac5c..3293be951834b 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 0fd5712eeba83..48b3f9e7aeca9 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 a4225e21edc84..67cb9a15526d3 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 ba8c0e56097db..aa84699b30c44 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 91a4d061d1c32..706550fe6c4e9 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 f217137f002fd..e51a9d95086bf 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 6f3b0c0e5c8a3..b4ac6eba9737e 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 cbc6201d0211d..ebc4f14045aa8 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 48120956d7d1d..c83e225ca2b36 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 f716dc46921a4..bc3aac63114d0 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 7cb5c7390c6fc..f624e73c99951 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 edcc84d5d614f..bc25a08940423 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 fdb7cfadbf33a..e3c80da5f23c0 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 462bedaa7aed0..ca0a39c3f125f 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 81899d42eed5d..5c5b945a957af 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 59132cd82ad8f..01a2108b3c78e 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 619a6b6211f2d..4eff08bdd6996 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 71c79c7b49499..393105f351496 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 f2d6acc38986d..7c586a3e0d844 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 ee9462d2ffb67..76c226045727a 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 d8a1df9d6a6bb..eeb3e1a2ac86e 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 0ec4e1e0c95a6..e2dd517e154e5 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 ec77f93d5c26b..25ab8413222ed 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 305c3b823f0f7..34a44e2baec0a 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 index 0f738e6888bb3..e16b7997cddbf 100644 --- a/third_party/rust/goblin/src/pe/authenticode.rs +++ b/third_party/rust/goblin/src/pe/authenticode.rs @@ -8,13 +8,9 @@ // - 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]; +use super::PE; impl PE<'_> { /// [`authenticode_ranges`] returns the various ranges of the binary that are relevant for @@ -23,7 +19,6 @@ impl PE<'_> { ExcludedSectionsIter { pe: self, state: IterState::default(), - sections: VecDeque::default(), } } } @@ -34,22 +29,19 @@ impl PE<'_> { pub(super) struct ExcludedSections { checksum: Range, datadir_entry_certtable: Range, - certificate_table_size: usize, - end_image_header: usize, + certtable: Option>, } impl ExcludedSections { pub(super) fn new( checksum: Range, datadir_entry_certtable: Range, - certificate_table_size: usize, - end_image_header: usize, + certtable: Option>, ) -> Self { Self { checksum, datadir_entry_certtable, - certificate_table_size, - end_image_header, + certtable, } } } @@ -57,26 +49,14 @@ impl ExcludedSections { 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), + DatadirEntry(usize), + CertTable(usize), + Final(usize), Done, } @@ -96,166 +76,24 @@ impl<'s> Iterator for ExcludedSectionsIter<'s> { 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; + self.state = IterState::DatadirEntry(sections.checksum.end); + return Some(&bytes[..sections.checksum.start]); } - 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::DatadirEntry(start) => { + self.state = IterState::CertTable(sections.datadir_entry_certtable.end); + return Some(&bytes[start..sections.datadir_entry_certtable.start]); } - 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); + 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 { - 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); + self.state = IterState::Final(start) } } - IterState::Padding(pad_size) => { + IterState::Final(start) => { 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]); - } + return Some(&bytes[start..]); } IterState::Done => return None, } diff --git a/third_party/rust/goblin/src/pe/certificate_table.rs b/third_party/rust/goblin/src/pe/certificate_table.rs index be45ce48dcef1..353a6c70ce320 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 index e65db5953d7a5..265e4e27f7bed 100644 --- a/third_party/rust/goblin/src/pe/data_directories.rs +++ b/third_party/rust/goblin/src/pe/data_directories.rs @@ -1,8 +1,5 @@ use crate::error; -use scroll::{ - ctx::{self}, - Pread, Pwrite, SizeWith, -}; +use scroll::{Pread, Pwrite, SizeWith}; #[repr(C)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] @@ -16,86 +13,14 @@ 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(), - )) - } - }) + let dd = bytes.gread_with(offset, scroll::LE)?; + Ok(dd) } } #[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) - } - }; + pub data_directories: [Option; NUM_DATA_DIRECTORIES], } impl DataDirectories { @@ -112,42 +37,70 @@ impl DataDirectories { let dd = if dd.virtual_address == 0 && dd.size == 0 { None } else { - Some((*offset, dd)) + Some(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))) + 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 06e23c0b037e3..c1ded9dd9ff7b 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 2336fddc570d0..5a7337630a5d3 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 852f4dced0f5e..b1d3192764ea9 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 4461a4c7bd1f7..5fea632f759f2 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 f49c2b689ccc8..4491827f166c0 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 e5aba25beca7f..b2ced808a1223 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 289ccc529b854..07a320d57b240 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 487d8d4279140..dc7b8080f0389 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 985beded51faa..6b252c67732cf 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 c4c928386b1b7..e12f6cc979d80 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 b71644917fd4e..1b75d43675046 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 cba72669159b2..078a477fb23d7 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 1fd0de1eed8b1..afc48acd03ce5 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 8da012b8c04a6..94bb35d12ac02 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 e38dc45c481c5..0000000000000 --- 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 c8d8187c8d2eb..4f128a62f9fdc 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 eddd8fd25c54f..c03f520974fb8 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 619a9d13cafca..8a2b63f314704 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 71d72079b74c8..b04e6ed6c60a3 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 2cf26b73195bd..0d99de9cc1493 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 index 4cdf2841c7873..406f97faa2907 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 0000000000000..bae87ee5909ee --- /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 0000000000000..baf29fe049664 --- /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 70e9e8d1c3664..548be72db9263 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 50dde54d7eba3..717fe6a23419d 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 0000000000000..0787dbe14bf1d --- /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 0000000000000..667f4b18f0dc5 --- /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 e24d2dc506754..1f982b82fa405 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 7b83c348d5fe7..06d7a1dc1c0e7 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 1b68c2e4c7306..774025477468c 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 eceec6d16613b..43f50b95f1769 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 636bf2553e792..46ef4c5b11a5c 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 27406485174a6..dcb58e7564f6d 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 15bf1426be3f2..72ba877054446 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 7a07f2dabaa73..ab6d96157d46b 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 0000000000000..e10726f22a200 --- /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 index b881da6c6a803..8c6b3b87c4fe4 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 9e2e33bd78cfd..71f40a7e6c97c 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 675b6d7803354..a7f7e85f0e7d4 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 c553a4a2c69db..0000000000000 --- 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 44fc03df30997..0000000000000 --- 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 124067f7aee7b..0000000000000 --- 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 7d45acfeef378..0000000000000 --- 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 e48af5fe9dc68..0000000000000 --- 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 24e4ea784ecd1..0000000000000 --- 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 1ec0ca35a755e..0000000000000 --- 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 367d0337dcb9d..0000000000000 --- 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 dbc80e15170d0..0000000000000 --- 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 9df8b9c824d34..0000000000000 --- 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 2e0343a59a479..0000000000000 --- 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 c9881eaeac49e..0000000000000 --- 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 67058a75a5048..0000000000000 --- 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 50a932fbeb2ed..0000000000000 --- 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 288592d02f1fa..0000000000000 --- 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 index 120a503f297e5..4bb3d097c5aa8 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 cec02ceadf491..17ce1af26d089 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 2e328e58040af..0000000000000 --- 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 45150d8413a9d..0000000000000 --- 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 f5a21fd9cc1aa..0000000000000 --- 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 bbefc6a00a862..0000000000000 --- 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 eb3b2e8abe59f..0000000000000 --- 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 14ca3d9462b91..0000000000000 --- 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 0412c50d8facd..426b1bf09882c 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 15746614d0082..23775b7decbd7 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 4a733ece9df9b..a403c1004c8fd 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 b304363de5007..025a959054b93 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 c55cffc7f52f2..4c925e5482d10 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 4a4e3fe9a058b..133cc56f141d2 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 c0b45524c739a..02a169df15f57 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 723c4c4384e10..5f995892d5da7 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 943bee58ae9d1..86f7da91f85d2 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 a9adbf92141ce..1f1fa20bfa4be 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 84a5c7ad3330d..c06ad84ca98f7 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 09486838281c7..0000000000000 --- 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 362c0c0b9da21..0000000000000 --- 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 98b642073e1c1..0000000000000 --- 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 1493f0a8a9859..0000000000000 --- 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 0d37ec3891d86..0000000000000 --- 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 bf13cd0957c86..0000000000000 --- 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 c1578aafbcf29..0000000000000 --- 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 d14d5588fa26e..0000000000000 --- 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 6b07f763c8a25..0000000000000 --- 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 fbcaab9e210b6..0000000000000 --- 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 b7ad4812a2f8a..0000000000000 --- 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 2f3a853b3cfd9..0000000000000 --- 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 32611c0938c45..0000000000000 --- 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 0514fe5fc0dfd..0000000000000 --- 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 80e420d195c1f..0000000000000 --- 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 1be85f04eb39b..0000000000000 --- 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 5c66191b771ee..0000000000000 --- 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 e06e9b88aa3df..0000000000000 --- 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 e2dc6aa01f934..0000000000000 --- 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 a7f2ccf298468..0000000000000 --- 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 7737e08f99544..0000000000000 --- 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 bdc0334539eeb..0000000000000 --- 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 9dd5ad2642d48..0000000000000 --- 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 3f429b187adb4..0000000000000 --- 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 2b4a10002a352..0000000000000 --- 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 857c779d676a6..0000000000000 --- 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 261eeb9e9f8b2..0000000000000 --- 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 ca473d8494d54..0000000000000 --- 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 c73819f069df3..0000000000000 --- 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 1a5d16b5ce8f6..0000000000000 --- 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 33a5447821095..24e445a094c61 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 52f08bb9f62c0..4efddceb0a70c 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 52b8ef33dbc05..43ff278460952 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 b9c8a0beb69ba..b9fe377732fd9 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 fd6772be24900..a40e2af6ecab9 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 90fdff684e4da..8b1280d82398b 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 @@ 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 2f1f261a13271..87e0d96e40d96 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 44d9628df496f..64232cf2d204a 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 0b47c0fa5a28e..ecfcc1e527d6f 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 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 faa4062019bea..0121f6e0f91a9 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 @@ 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 8a890fb65cf30..3542d7cfd71f1 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 c6dc9d1f4b4a2..6caed17ab1027 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 index d04742e076bea..5142c2fc42e94 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) +assert sempty.get_position() == Point(0, 0) -s = Sprite(Point(x=0, y=1)) -assert s.get_position() == Point(x=0, y=1) +s = Sprite(Point(0, 1)) +assert s.get_position() == Point(0, 1) -s.move_to(Point(x=1, y=2)) -assert s.get_position() == Point(x=1, y=2) +s.move_to(Point(1, 2)) +assert s.get_position() == Point(1, 2) -s.move_by(Vector(dx=-4, dy=2)) -assert s.get_position() == Point(x=-3, y=4) +s.move_by(Vector(-4, 2)) +assert s.get_position() == Point(-3, 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) +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 index fa73043979ea5..9d79b57026f9b 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 @@ -7,16 +7,16 @@ include Sprites sempty = Sprite.new(nil) -assert_equal sempty.get_position, Point.new(x: 0, y: 0) +assert_equal sempty.get_position, Point.new(0, 0) -s = Sprite.new(Point.new(x: 0, y: 1)) -assert_equal s.get_position, Point.new(x: 0, y: 1) +s = Sprite.new(Point.new(0, 1)) +assert_equal s.get_position, Point.new(0, 1) -s.move_to(Point.new(x: 1, y: 2)) -assert_equal s.get_position, Point.new(x: 1, y: 2) +s.move_to(Point.new(1, 2)) +assert_equal s.get_position, Point.new(1, 2) -s.move_by(Vector.new(dx: -4, dy: 2)) -assert_equal s.get_position, Point.new(x: -3, y: 4) +s.move_by(Vector.new(-4, 2)) +assert_equal s.get_position, Point.new(-3, 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) +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 6b3a53fc5ed93..a0bf1d826c810 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 cf4de491cd7a8..9421e726a0ca8 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 7b676c83de236..017e999fb287c 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 @@ 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 @@ 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 fc1a823f52a5e..d9e04f92e7b79 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 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 @@ 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 @@ 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 index 98c4aca54e985..74d539b50574d 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 374e3655028b8..475c8ab9be7ee 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 64ac3486a3bfe..0000000000000 --- 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 77d7f219a9209..b2d3adc2aee6a 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 319b3c783627c..0625bd9c66f51 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 index 40b0b6e3ccdf9..880d79a96fde2 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 f0c7af866550a..9469a9cf25e05 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 64ac3486a3bfe..0000000000000 --- 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 f4dde0e4203e7..0d2da8cab2ea0 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 ae4bffc9732f1..e20020e87c725 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 index 8d075bbedb921..4329f32f4c376 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 @@ -5,81 +5,55 @@ use super::{AsCodeType, CodeType}; use crate::backend::{Literal, Type}; use crate::ComponentInterface; +use paste::paste; -#[derive(Debug)] -pub struct OptionalCodeType { - inner: Type, -} +fn render_literal(literal: &Literal, inner: &Type, ci: &ComponentInterface) -> String { + match literal { + Literal::Null => "null".into(), + Literal::EmptySequence => "listOf()".into(), + Literal::EmptyMap => "mapOf()".into(), -impl OptionalCodeType { - pub fn new(inner: Type) -> Self { - Self { inner } - } - fn inner(&self) -> &Type { - &self.inner + // For optionals + _ => super::KotlinCodeOracle.find(inner).literal(literal, ci), } } -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:?}"), +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) + } + } } } -} + } -#[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:?}"), - } - } -} +impl_code_type_for_compound!(OptionalCodeType, "{}?", "Optional{}"); +impl_code_type_for_compound!(SequenceCodeType, "List<{}>", "Sequence{}"); #[derive(Debug)] pub struct MapCodeType { @@ -118,10 +92,7 @@ impl CodeType for MapCodeType { ) } - fn literal(&self, literal: &Literal, _ci: &ComponentInterface) -> String { - match literal { - Literal::EmptyMap => "mapOf()".into(), - _ => panic!("Invalid literal for Map type: {literal:?}"), - } + 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 0000000000000..154e12a381096 --- /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 d55c78f760b2f..3ecf09d47f5a3 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 c4fc8e0ed6afb..1ed0575a9a517 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/object.rs b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs index 5a4305d14ae0d..c39ae59cce9a4 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/kotlin/gen_kotlin/object.rs @@ -3,32 +3,25 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use super::CodeType; -use crate::{interface::ObjectImpl, ComponentInterface}; +use crate::ComponentInterface; #[derive(Debug)] pub struct ObjectCodeType { - name: String, - imp: ObjectImpl, + id: String, } impl ObjectCodeType { - pub fn new(name: String, imp: ObjectImpl) -> Self { - Self { name, imp } + pub fn new(id: String) -> Self { + Self { id } } } impl CodeType for ObjectCodeType { fn type_label(&self, ci: &ComponentInterface) -> String { - super::KotlinCodeOracle.class_name(ci, &self.name) + super::KotlinCodeOracle.class_name(ci, &self.id) } fn canonical_name(&self) -> String { - format!("Type{}", self.name) - } - - fn initialization_fn(&self) -> Option { - self.imp - .has_callback_interface() - .then(|| format!("uniffiCallbackInterface{}.register", self.name)) + format!("Type{}", 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 0bc5a5d99ea2b..22495fa209895 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 index b28fbd2c80dae..c6a32655f2b4c 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 const val UNIFFI_RUST_FUTURE_POLL_READY = 0.toShort() +internal const val UNIFFI_RUST_FUTURE_POLL_MAYBE_READY = 1.toShort() -internal val uniffiContinuationHandleMap = UniffiHandleMap>() +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 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: Long, - pollFunc: (Long, UniffiRustFutureContinuationCallback, Long) -> Unit, - completeFunc: (Long, UniffiRustCallStatus) -> F, - freeFunc: (Long) -> Unit, + rustFuture: Pointer, + pollFunc: (Pointer, USize) -> Unit, + completeFunc: (Pointer, RustCallStatus) -> F, + freeFunc: (Pointer) -> Unit, liftFunc: (F) -> T, - errorHandler: UniffiRustCallStatusErrorHandler + errorHandler: CallStatusErrorHandler ): T { try { do { - val pollResult = suspendCancellableCoroutine { continuation -> + 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) }) + rustCallWithError(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 %} 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 c6b266066d1b0..8cfa2ce0003c6 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 c9449069e26b1..4840a199b4b6d 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 30a39d9afb273..0000000000000 --- 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 d58a651e24035..62a71e02f15d1 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 index d2cdee4f33f10..5a29f0acc370a 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 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 aeb5f58002ed3..04150c5d78c52 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 62e02607f3498..4237c6f9a8cc1 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 8d1c2235ece55..d4c4a1684aeb6 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 4760c03fd6cf3..986db5424d0bc 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 b7e77f0b2de16..0fade7a0bc053 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 0de90b9c4b710..3b2c9d225a65c 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 be91ac8fcb8df..eafec5d122422 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 5eb465f0df9e3..9fc2892c955f2 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 0000000000000..3544b2f9e6ecc --- /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 3a5664819035a..0000000000000 --- 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 1fdbd3ffc0383..382a5f7413640 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 de8296fff6d62..75564276be884 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 171809a9c44ee..b7a8131c8b575 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 35cf8f3169063..601cfc7c2cb22 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 27c98a665965b..9237768dbf84f 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 0b4249fb11856..0000000000000 --- 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 a80418eb003a5..776c402727b12 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 1bac8a435c9e9..6a3aeada35ed9 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 e3e85544d7241..0000000000000 --- 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 d025879848896..0000000000000 --- 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 c43bc167fca76..0000000000000 --- 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 0000000000000..b9352c690fa72 --- /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 index 62cac7a4d012d..8ce27a5d04f0e 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,282 +1,125 @@ -// 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 %} +{%- 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") }} -{%- include "Interface.kt" %} +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 -%} -{%- 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 %} + {% endfor %} + companion object +} - 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)) - } +class {{ type_name }}( + pointer: Pointer +) : FFIObject(pointer), {{ type_name }}Interface { {%- 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) -%}) : + {%- when Some with (cons) %} + constructor({% call kt::arg_list_decl(cons) -%}) : 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() - } + /** + * 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) } } - // 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) - } - } + {% 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) } - } - fun uniffiClonePointer(): Pointer { - return uniffiRustCall() { status -> - UniffiLib.INSTANCE.{{ obj.ffi_object_clone().name() }}(pointer!!, status) + {%- when None -%} + override fun {{ meth.name()|fn_name }}({% call kt::arg_list_protocol(meth) %}) = + callWithPointer { + {%- call kt::to_ffi_call_with_prefix("it", meth) %} } - } - - {% for meth in obj.methods() -%} - {%- call kt::func_decl("override", meth, 4) %} + {% endmatch %} + {% endif %} {% 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) %} + fun {{ cons.name()|fn_name }}({% call kt::arg_list_decl(cons) %}): {{ type_name }} = + {{ type_name }}({% call kt::to_ffi_call(cons) %}) {% 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 %} - } +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 {{ impl_class_name }}(value) + return {{ type_name }}(value) } override fun read(buf: ByteBuffer): {{ type_name }} { @@ -285,7 +128,7 @@ public object {{ ffi_converter_name }}: FfiConverter<{{ type_name }}, Pointer> { return lift(Pointer(buf.getLong())) } - override fun allocationSize(value: {{ type_name }}) = 8UL + 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, 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 98451e14518f8..56cb5f87a54bb 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 0e770cb8294e8..0000000000000 --- 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 bc3028c736b6c..b588ca1398396 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 b28f25bfc373f..dfbea240741aa 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 61f911cb0c3fc..876d1bc05efea 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 b67435bd1ae6f..68324be4f9ecb 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 10a450a4bd849..21069d7ce8902 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 index 681c48093a192..6a841d3484f14 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 c27121b701e86..103d444ea3e5d 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 b179145b62714..279a8fa91be27 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 202d5bcd5bf70..da7b5b28d67fd 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 9be2a5a69dcc6..44d27ad36b126 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 ee360673e0d04..b6d176603e71d 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 index 7acfdc8861251..6a95d6a66dfe0 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,91 +1,32 @@ {# // Template to call into rust. Used in several places. -// Variable names in `arg_list` should match up with arg lists +// Variable names in `arg_list_decl` 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) }}) + rustCallWithError({{ e|type_name(ci) }}) {%- else %} - uniffiRustCall() + rustCall() {%- endmatch %} { _status -> - UniffiLib.INSTANCE.{{ func.ffi_func().name() }}( - {% if func.takes_self() %}it, {% endif -%} - {% call arg_list_lowered(func) -%} - _status) + _UniFFILib.INSTANCE.{{ func.ffi_func().name() }}({% 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 %} - ) +{%- 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) %} @@ -96,42 +37,37 @@ {#- // 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() -%} +{% macro arg_list_decl(func) %} + {%- 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 %} + {%- 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. +// 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 %} + {%- if func.has_rust_call_status_arg() %}_uniffi_out_err: RustCallStatus, {% 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( @@ -139,15 +75,3 @@ v{{- field_num -}} 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 %} 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 2cdc72a5e2ec4..9ee4229018616 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 0824015751550..7b78540741717 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 16adeca9a5032..b91bcbe18fc18 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/executor.rs b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/executor.rs new file mode 100644 index 0000000000000..be3ba1d791843 --- /dev/null +++ b/third_party/rust/uniffi_bindgen/src/bindings/python/gen_python/executor.rs @@ -0,0 +1,18 @@ +/* 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; + +#[derive(Debug)] +pub struct ForeignExecutorCodeType; + +impl CodeType for ForeignExecutorCodeType { + fn type_label(&self) -> String { + "asyncio.BaseEventLoop".into() + } + + fn canonical_name(&self) -> String { + "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 0a46251d6d9a7..0d19c4bb3c6e2 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 6a10a38e7ffad..8178fcc102983 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 index 26daa9ba5cf83..82aa534b46ecb 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 @@ -3,37 +3,13 @@ _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() +_UniffiContinuationPointerManager = _UniffiPointerManager() # 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 +@_UNIFFI_FUTURE_CONTINUATION_T def _uniffi_continuation_callback(future_ptr, poll_code): - (eventloop, future) = _UniffiContinuationHandleMap.remove(future_ptr) + (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): @@ -42,15 +18,14 @@ def _uniffi_set_future_result(future, 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() + 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, - _uniffi_continuation_callback, - _UniffiContinuationHandleMap.insert((eventloop, future)), + _UniffiContinuationPointerManager.new_pointer((eventloop, future)), ) poll_code = await future if poll_code == _UNIFFI_RUST_FUTURE_POLL_READY: @@ -62,53 +37,4 @@ async def _uniffi_rust_call_async(rust_future, ffi_poll, ffi_complete, ffi_free, 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 %} +_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 3f8c5d1d4db62..6775e9e132e14 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 4d09531322b22..196b5b29fa992 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 @@ def read(buf): 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 676f01177a1c8..0000000000000 --- 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 d802c90fdecfe..0fe2ab8dc004b 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,22 +45,28 @@ _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): handle = buf.read_u64() cls.lift(handle) - @classmethod - def check_lower(cls, cb): - pass - @classmethod def lower(cls, cb): handle = cls._handle_map.insert(cb) 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 index a41e58e635c9f..e0e926757a7fe 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() %} +{%- let cbi = ci|get_callback_interface_definition(id) %} +{%- let foreign_callback = format!("foreignCallback{}", canonical_type_name) %} -{% include "Protocol.py" %} -{% include "CallbackInterfaceImpl.py" %} +{% 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 }} = UniffiCallbackInterfaceFfiConverter() +{{ 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 f75a85dc27565..5be6155b84996 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 @@ -17,10 +17,6 @@ def read(buf): def lift(value): 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) @@ -55,11 +51,6 @@ def lift(value): builtin_value = {{ builtin|lift_fn }}(value) 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") }} 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 ecb035b7f40c0..10974e009db24 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 @@ -11,15 +11,11 @@ def read(buf): microseconds = buf.read_u32() / 1.0e3 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 d07dd1c44adbf..84d089baf9f95 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 @@ def __eq__(self, other): return False {%- endfor %} return True - {% endif %} {% endfor %} # For each variant, we have an `is_NAME` method for easily checking @@ -110,30 +81,6 @@ def read(buf): {%- 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 @@ def write(value, buf): 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 0911ff559a526..26a1e6452a53f 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([ @@ -64,20 +59,6 @@ def read(buf): {%- 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 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() %} 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 6c0cee85ef3a0..71e05e8b0634f 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 49a1a7286efae..a52107a6381bd 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 @@ def read(buf): 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 e2084c7b13ec5..772f5080e9787 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 @@ def read(buf): 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 0000000000000..6a6932fed06fc --- /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 f7c13cf745537..0000000000000 --- 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 5d4bcbba89971..dca962f176c34 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 befa5633846da..99f19dc1c006a 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 @@ def read(buf): 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 70644f6717148..3b142c8749e7f 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 @@ def read(buf): 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 232f127bd6ed2..6e94379cbf931 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 @@ def read(buf): 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 c1de1625e73d7..732530e3cb180 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 @@ def read(buf): 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 a09ca28a30aa8..387227ed098e6 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 @@ -2,12 +2,6 @@ {%- let value_ffi_converter = value_type|ffi_converter_name %} 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)) 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 1929f9aad6fec..fac6cd556438c 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,5 +1,21 @@ # 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 """ @@ -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 18dca4743ade7..7e98f7c46f650 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 @@ def __del__(self): 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 @@ def _make_instance_(cls, pointer): {%- 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 @@ def __eq__(self, other: object) -> {{ eq.return_type().unwrap()|type_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 4c07ae3e346f3..e406c51d4928e 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 @@ -1,11 +1,6 @@ {%- let inner_ffi_converter = inner_type|ffi_converter_name %} 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: 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 0000000000000..23aa28eab44cc --- /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 3b7e93596aca2..0000000000000 --- 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 0b5634eb526e2..99a30e120fefd 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 @@ def __init__(self, *, {% for field in rec.fields() %} 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 %}) @@ -46,22 +42,8 @@ def read(buf): {%- endfor %} ) - @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 4db74fb157172..daabd5b4b9b3b 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 @@ def check_lower(cls, value): 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 44e0ba1001b20..c317a632fce32 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,15 +1,11 @@ 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 @@ def read_float(self): 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 3c30d9f9f50e3..3c9f5a45961a5 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 @@ -1,11 +1,6 @@ {%- let inner_ffi_converter = inner_type|ffi_converter_name %} 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) 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 d574edd09fa8d..40890b6abc169 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 @@ def read(buf): @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 @@ def lift(buf): @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 76d7f8bcdbaa3..8402f6095d38b 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 @@ -17,10 +17,6 @@ def read(buf): else: 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): 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 230b9e853f838..f258b60a1c0ac 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 4aaed253e018b..5e05314c37a57 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 039bf76162f88..081c6731ce960 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 @@ def read(buf): 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 1650bf9b609fd..b80e75177d48a 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 @@ def read(buf): 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 f354545e26be6..4b87e58547fa1 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 @@ def read(buf): 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 cee130b4d90f3..33026706f26c8 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 @@ def read(buf): 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 6818a8c107087..ef3b1bb94d348 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 @@ {%- 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 @@ 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 @@ 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 @@ {%- 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 @@ async def {{ py_method_name }}(self, {% call arg_list_decl(meth) %}) -> None: {%- 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 @@ async def {{ py_method_name }}(self, {% call arg_list_decl(meth) %}) -> None: {%- 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 1ccd6821c00ba..24c3290ff7c1d 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 struct import contextlib import datetime -import threading -import itertools -import traceback import typing {%- if ci.has_async_fns() %} import asyncio @@ -40,20 +34,20 @@ {% 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 @@ {%- 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 0c23140b3326c..0fcf09996f129 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 04841b459c9f9..1f1bf8e299d36 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 ba2caf7380720..677c5c729bf85 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 @@ def self.uniffi_define_finalizer_by_pointer(pointer, object_id) # 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 @@ def self.{{ cons.name()|fn_name_rb }}({% call rb::arg_list_decl(cons) %}) {%- 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 b5a201b248b9a..c940b3106053f 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 d15c0bbe762f4..8749139116bf4 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 @@ def write_{{ canonical_type_name }}(v) # 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 f9b0806abc4a8..b085dddf15e86 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 @@ def read{{ canonical_type_name }} 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 @@ def read{{ canonical_type_name }} 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 452d9831cded5..0194c9666def6 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 @@ def consumeInto{{ canonical_type_name }} {%- 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 @@ def consumeInto{{ canonical_type_name }} {%- 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 @@ def consumeInto{{ canonical_type_name }} {% 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 @@ def consumeInto{{ canonical_type_name }} {% 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 @@ def consumeInto{{ canonical_type_name }} {% 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 b6dce0effab40..13214cf31b536 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 @@ def self.{{ func.name()|fn_name_rb }}({%- call rb::arg_list_decl(func) -%}) {% 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 59fa4ef4cc271..8dc3e5e613b52 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 88f770b9dc329..03da37d567a0b 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 dab89e0259d4b..5d8b37e0af9bf 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 d89fdfd386463..8e6dddf3f9181 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/swift/gen_swift/executor.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs new file mode 100644 index 0000000000000..b488b004cfe73 --- /dev/null +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/executor.rs @@ -0,0 +1,23 @@ +/* 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; + +#[derive(Debug)] +pub struct ForeignExecutorCodeType; + +impl CodeType for ForeignExecutorCodeType { + fn type_label(&self) -> String { + // On Swift, we define a struct to represent a ForeignExecutor + "UniFfiForeignExecutor".into() + } + + fn canonical_name(&self) -> String { + "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 3960b7aae148b..0b6728ba840e3 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 16c162512367b..12db4afc66644 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/swift/gen_swift/object.rs b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs index d4497a7b19734..ea140c998d39e 100644 --- a/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs +++ b/third_party/rust/uniffi_bindgen/src/bindings/swift/gen_swift/object.rs @@ -3,32 +3,24 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use super::CodeType; -use crate::interface::ObjectImpl; #[derive(Debug)] pub struct ObjectCodeType { - name: String, - imp: ObjectImpl, + id: String, } impl ObjectCodeType { - pub fn new(name: String, imp: ObjectImpl) -> Self { - Self { name, imp } + pub fn new(id: String) -> Self { + Self { id } } } impl CodeType for ObjectCodeType { fn type_label(&self) -> String { - super::SwiftCodeOracle.class_name(&self.name) + super::SwiftCodeOracle.class_name(&self.id) } fn canonical_name(&self) -> String { - format!("Type{}", self.name) - } - - fn initialization_fn(&self) -> Option { - self.imp - .has_callback_interface() - .then(|| format!("uniffiCallbackInit{}", 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 e0c670520ed34..86424658a3b2b 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 index e16f3108e1b62..695208861d639 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,13 +1,11 @@ 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) -> (), + rustFutureFunc: () -> UnsafeMutableRawPointer, + pollFunc: (UnsafeMutableRawPointer, UnsafeMutableRawPointer) -> (), + completeFunc: (UnsafeMutableRawPointer, UnsafeMutablePointer) -> F, + freeFunc: (UnsafeMutableRawPointer) -> (), liftFunc: (F) throws -> T, errorHandler: ((RustBuffer) throws -> Error)? ) async throws -> T { @@ -21,11 +19,7 @@ fileprivate func uniffiRustCallAsync( var pollResult: Int8; repeat { pollResult = await withUnsafeContinuation { - pollFunc( - rustFuture, - uniffiFutureContinuationCallback, - uniffiContinuationHandleMap.insert(obj: $0) - ) + pollFunc(rustFuture, ContinuationHolder($0).toOpaque()) } } while pollResult != UNIFFI_RUST_FUTURE_POLL_READY @@ -37,80 +31,32 @@ fileprivate func uniffiRustCallAsync( // 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") - } +fileprivate func uniffiFutureContinuationCallback(ptr: UnsafeMutableRawPointer, pollResult: Int8) { + ContinuationHolder.fromOpaque(ptr).resume(pollResult) } -{%- 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) +// Wraps UnsafeContinuation in a class so that we can use reference counting when passing it across +// the FFI +fileprivate class ContinuationHolder { + let continuation: UnsafeContinuation -} - -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))) - } + init(_ continuation: UnsafeContinuation) { + self.continuation = continuation } - 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() -} + func resume(_ pollResult: Int8) { + self.continuation.resume(returning: pollResult) + } -extension Task: UniffiForeignFutureTask {} + func toOpaque() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } -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") + static func fromOpaque(_ ptr: UnsafeRawPointer) -> ContinuationHolder { + return Unmanaged.fromOpaque(ptr).takeRetainedValue() } } -// For testing -public func uniffiForeignFutureHandleCount{{ ci.namespace()|class_name }}() -> Int { - UNIFFI_FOREIGN_FUTURE_HANDLE_MAP.count +fileprivate func uniffiInitContinuationCallback() { + {{ ci.ffi_rust_future_continuation_callback_set().name() }}(uniffiFutureContinuationCallback) } - -{%- endif %} 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 89d98594d3990..87698e359fa85 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 74ee3726422d9..0000000000000 --- 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 5863c2ad41e19..9ae62d1667e98 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 7aa1cca9b25af..aec8ded930ef6 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 1d8b3cf500f44..99f45290cc66c 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 0702c477e9400..786091395bcd2 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 0000000000000..167e4c7546052 --- /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 6de9f085d616d..0000000000000 --- 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 cfddf7b3139f5..a34b128e2363d 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 index 0c28bc4c0959f..57a77ca6dfce6 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,146 +1,104 @@ {%- 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() {} - } +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 public init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) { + required 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) %} + public convenience init({% call swift::arg_list_decl(cons) -%}) {% call swift::throws(cons) %} { + self.init(unsafeFromRawPointer: {% call swift::to_ffi_call(cons) %}) + } {%- 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) %} + 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 %} - {%- 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) %} + {# // 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 %} ) } - {%- 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) %} + + {% 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 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) + + {%- 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) %} } - {%- else %} - {%- endmatch %} - {%- endfor %} + {%- endmatch -%} + {%- endif -%} + {% 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. @@ -157,30 +115,15 @@ public struct {{ ffi_converter_name }}: FfiConverter { // 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 lift(_ pointer: UnsafeMutableRawPointer) throws -> {{ type_name }} { + return {{ type_name}}(unsafeFromRawPointer: pointer) } - public static func write(_ value: {{ type_name }}, into buf: inout [UInt8]) { - fatalError("not implemented") + public static func lower(_ value: {{ type_name }}) -> UnsafeMutableRawPointer { + return value.pointer } } -{%- endif %} {# We always write these public functions just in case the enum is used as 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 7df953558aa20..0000000000000 --- 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 c262a7a2166fe..44de9dd358bd1 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 a053334a3022f..2f737b6635142 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 index ce946076f7010..a2c6311931e4e 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 5e26758f3c359..aba34f4b0bd49 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 index 8692cd6ff0712..0a125e6f619ae 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 @@ -8,97 +8,28 @@ {%- call try(func) -%} {%- match func.throws_type() -%} {%- when Some with (e) -%} - rustCallWithError({{ e|ffi_error_converter_name }}.lift) { + rustCallWithError({{ e|ffi_converter_name }}.lift) { {%- else -%} rustCall() { {%- endmatch %} - {{ func.ffi_func().name() }}( - {%- if func.takes_self() %}self.uniffiClonePointer(),{% endif %} - {%- call arg_list_lowered(func) -%} $0 - ) + {{ func.ffi_func().name() }}({% 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() +{%- 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 %} - let pointer = - {% call to_ffi_call(callable) %} - {%- endif %} - self.init(unsafeFromRawPointer: pointer) + rustCall() { + {% endmatch %} + {{ func.ffi_func().name() }}( + {{- prefix }}, {% call arg_list_lowered(func) -%} $0 + ) } {%- 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 }}), @@ -125,30 +56,17 @@ public convenience init( // 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) %} +{% macro field_list_decl(item) %} {%- 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() -%} @@ -157,26 +75,15 @@ v{{- field_num -}} {%- endfor %} {%- endmacro %} + {%- macro async(func) %} -{%- if func.is_async() %}async {% endif %} +{%- if func.is_async() %}async{% endif %} {%- endmacro -%} {%- macro throws(func) %} -{%- if func.throws() %}throws {% endif %} +{%- 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 %} 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 17fdde74e07a9..c34d348efb47f 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 195a77696b9b6..c3b2f152771d2 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 index f176a7a684d1e..e3bca4f9664a0 100644 --- a/third_party/rust/uniffi_bindgen/src/interface/callbacks.rs +++ b/third_party/rust/uniffi_bindgen/src/interface/callbacks.rs @@ -33,12 +33,9 @@ //! # Ok::<(), anyhow::Error>(()) //! ``` -use std::iter; - -use heck::ToUpperCamelCase; use uniffi_meta::Checksum; -use super::ffi::{FfiArgument, FfiCallbackFunction, FfiField, FfiFunction, FfiStruct, FfiType}; +use super::ffi::{FfiArgument, FfiFunction, FfiType}; use super::object::Method; use super::{AsType, Type, TypeIterator}; @@ -55,11 +52,18 @@ pub struct CallbackInterface { // 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 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 } @@ -73,45 +77,18 @@ impl CallbackInterface { } 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() + 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)) } - - 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 { @@ -123,139 +100,6 @@ impl AsType for CallbackInterface { } } -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; @@ -302,21 +146,4 @@ mod test { 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" - ); - } } diff --git a/third_party/rust/uniffi_bindgen/src/interface/enum_.rs b/third_party/rust/uniffi_bindgen/src/interface/enum_.rs index a666cc3605fc1..82baf1dd50f8e 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 b27cb7847718e..d18aaf8262a77 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 8effc4c87665d..2d18288c1c6fe 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 90a941637a58a..8e4df2149b4fa 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 2b86e54a45133..942032b3c6c03 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 e9a600418968e..17d3774a49d74 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 70bc61f8a9faf..e69d86e44faf3 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 dfc90b32a6c12..019b24022fd3d 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 c460c03d9f481..f170ea5e918bc 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 69fad1980e905..7ce6c3a70ba8e 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 6d440919f16b4..25b5ef17ba27d 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 7fd81831aaf63..f3759cf6faff8 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 index 658f4c8de527d..64c69e4d8e87c 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 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() %} - 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 %} - ) + + {#- 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|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 %} + {%- 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 f918ef2f3a550..6b9f96f2248de 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 64f48e233497c..94538ecaa898c 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 d67e172cc26f2..ade1578897a80 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 e752878af59bc..e2445c670d971 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 a7affdf7b84ab..85e131dd8cf7c 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 27f3686b9f628..eeee0f5ee2972 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 a9005a0f5850e..8e585bfa958de 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 fed51c34ca2b1..3fe7ee5cf0d07 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 64ac3486a3bfe..0000000000000 --- 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 5e211378a08a6..9df6eba7b4ab9 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 681c8846e199c..a3c4ed7ca3420 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 64ac3486a3bfe..0000000000000 --- 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 index 573f7a72c9393..59804f7c89cc0 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 ce36a2168a497..4d4cbe27581e5 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 64ac3486a3bfe..0000000000000 --- 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 e7a4faab64b0e..7be66880bb820 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 a992ab73843b4..1f86f6b13b3d5 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 326ff127473bb..ac2463cd8ed50 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 0000000000000..7b1cb9bd802c6 --- /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 be6a214e84173..0000000000000 --- 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 8ee2f46c359d9..0000000000000 --- 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 acaf2b0d06fa1..b606323297275 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 8b2972968c685..e09e3be89a119 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,9 +241,26 @@ 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(); @@ -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, || { @@ -320,6 +392,24 @@ mod test { rbuf.destroy_into_vec(); } + #[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() { diff --git a/third_party/rust/uniffi_core/src/ffi/rustcalls.rs b/third_party/rust/uniffi_core/src/ffi/rustcalls.rs index 16b0c76f2edc2..53265393c0598 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 0000000000000..0c1a24174bbce --- /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 93c34e7543c40..0000000000000 --- 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 3d3505e5ef117..0000000000000 --- 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 629ee0c1092b6..0000000000000 --- 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 886ee27c71542..0000000000000 --- 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 aec093154ab88..af18f3873ba16 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 4e7b9e06fa80f..3b5914e32f417 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 1f3a2403f8267..c84b403dced14 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 dc61a1bfcbc73..770d2b36d5e06 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 index 9db049289cc0b..96e44ac74eca9 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 5ae193e392731..9d3908ae8dadf 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 64ac3486a3bfe..0000000000000 --- 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 000c205845791..0000000000000 --- 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 index fd98da31299b0..32abfa08ccb7d 100644 --- a/third_party/rust/uniffi_macros/src/enum_.rs +++ b/third_party/rust/uniffi_macros/src/enum_.rs @@ -1,47 +1,13 @@ 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 syn::{Data, DataEnum, DeriveInput, Field, Index}; 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, + create_metadata_items, derive_all_ffi_traits, ident_to_string, mod_path, tagged_impl_header, + try_metadata_value_from_usize, try_read_field, }; -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 { +pub fn expand_enum(input: DeriveInput, udl_mode: bool) -> syn::Result { let enum_ = match input.data { Data::Enum(e) => e, _ => { @@ -52,17 +18,10 @@ pub fn expand_enum( } }; 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 ffi_converter_impl = enum_ffi_converter_impl(ident, &enum_, udl_mode); 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) + enum_meta_static_var(ident, &enum_).unwrap_or_else(syn::Error::into_compile_error) }); Ok(quote! { @@ -75,13 +34,11 @@ 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 }, ) } @@ -90,13 +47,11 @@ 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 }, ) } @@ -105,7 +60,6 @@ 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); @@ -115,50 +69,19 @@ fn enum_or_error_ffi_converter_impl( 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),* } } - }; + 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)* - } + 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)* } }; @@ -166,17 +89,10 @@ fn enum_or_error_ffi_converter_impl( 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)* }, - } + quote! { + #idx => Self::#v_ident { #(#try_read_fields)* }, } }); let error_format_string = format!("Invalid {ident} enum value: {{}}"); @@ -211,161 +127,69 @@ fn enum_or_error_ffi_converter_impl( } } -pub(crate) fn enum_meta_static_var( - ident: &Ident, - docstring: String, - discr_type: Option, - enum_: &DataEnum, - attr: &EnumAttr, -) -> syn::Result { +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 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 + .chain( + enum_.variants .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) - }) - })) + .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() } - -#[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)?, - }) - } -} diff --git a/third_party/rust/uniffi_macros/src/error.rs b/third_party/rust/uniffi_macros/src/error.rs index 804b43800332f..a2ee7cf603252 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 41657a639e42e..bbb16acf9019a 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 index be7e8902e4407..c3edcd5920293 100644 --- a/third_party/rust/uniffi_macros/src/export/attributes.rs +++ b/third_party/rust/uniffi_macros/src/export/attributes.rs @@ -1,33 +1,31 @@ -use std::collections::{HashMap, HashSet}; - -use crate::{ - default::DefaultValue, - util::{either_attribute_arg, kw, parse_comma_separated, UniffiAttributeArgs}, -}; +use crate::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, + Attribute, LitStr, Meta, PathArguments, PathSegment, Token, }; -use uniffi_meta::UniffiTraitDiscriminants; #[derive(Default)] -pub struct ExportTraitArgs { +pub struct ExportAttributeArguments { pub(crate) async_runtime: Option, pub(crate) callback_interface: Option, - pub(crate) with_foreign: 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 ExportTraitArgs { +impl Parse for ExportAttributeArguments { fn parse(input: ParseStream<'_>) -> syn::Result { parse_comma_separated(input) } } -impl UniffiAttributeArgs for ExportTraitArgs { +impl UniffiAttributeArgs for ExportAttributeArguments { fn parse_one(input: ParseStream<'_>) -> syn::Result { let lookahead = input.lookahead1(); if lookahead.peek(kw::async_runtime) { @@ -42,175 +40,52 @@ impl UniffiAttributeArgs for ExportTraitArgs { callback_interface: input.parse()?, ..Self::default() }) - } else if lookahead.peek(kw::with_foreign) { + } else if lookahead.peek(kw::constructor) { Ok(Self { - with_foreign: input.parse()?, + constructor: 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()?; + } else if lookahead.peek(kw::Debug) { Ok(Self { - async_runtime: Some(input.parse()?), + trait_debug: 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()); + } else if lookahead.peek(kw::Display) { Ok(Self { - name, + trait_display: input.parse()?, ..Self::default() }) - } else if lookahead.peek(kw::default) { + } else if lookahead.peek(kw::Hash) { Ok(Self { - defaults: DefaultMap::parse(input)?, + trait_hash: input.parse()?, ..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()?; + } else if lookahead.peek(kw::Eq) { Ok(Self { - async_runtime: Some(input.parse()?), + trait_eq: input.parse()?, + ..Self::default() }) } else { - Err(syn::Error::new( - input.span(), - format!("uniffi::export attribute `{input}` is not supported here."), - )) + 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)?, }) } } -#[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), } @@ -236,57 +111,9 @@ impl ToTokens for AsyncRuntime { } } -/// 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 { @@ -303,11 +130,12 @@ impl ExportedImplFnAttributes { } ensure_no_path_args(fst)?; - let args = match &attr.meta { - Meta::List(_) => attr.parse_args::()?, - _ => Default::default(), - }; - this.args = args; + 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( @@ -328,14 +156,6 @@ impl ExportedImplFnAttributes { } 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")), } } @@ -351,53 +171,3 @@ fn ensure_no_path_args(seg: &PathSegment) -> syn::Result<()> { 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()?, - }) - } -} diff --git a/third_party/rust/uniffi_macros/src/export/callback_interface.rs b/third_party/rust/uniffi_macros/src/export/callback_interface.rs index fe145384ec732..2f2561bbc2232 100644 --- a/third_party/rust/uniffi_macros/src/export/callback_interface.rs +++ b/third_party/rust/uniffi_macros/src/export/callback_interface.rs @@ -5,125 +5,57 @@ use crate::{ export::ImplItem, fnsig::{FnKind, FnSignature, ReceiverArg}, - util::{ - create_metadata_items, derive_ffi_traits, ident_to_string, mod_path, tagged_impl_header, - }, + util::{create_metadata_items, ident_to_string, mod_path, tagged_impl_header}, }; use proc_macro2::{Span, TokenStream}; -use quote::{format_ident, quote}; +use quote::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, + ident: &Ident, trait_ident: &Ident, + internals_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 + let trait_impl_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), + ImplItem::Method(sig) => gen_method_impl(sig, internals_ident), + _ => unreachable!("traits have no constructors"), }) - .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] }); + .collect::>()?; + let ffi_converter_tokens = ffi_converter_callback_interface_impl(trait_ident, ident, false); 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); - } - + #[doc(hidden)] #[derive(Debug)] - struct #trait_impl_ident { + struct #ident { handle: u64, } - impl #trait_impl_ident { + 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 { + impl ::std::ops::Drop for #ident { fn drop(&mut self) { - let vtable = #vtable_cell.get(); - (vtable.uniffi_free)(self.handle); + #internals_ident.invoke_callback::<(), crate::UniFfiTag>( + self.handle, uniffi::IDX_CALLBACK_FREE, Default::default() + ) } } - }) -} -pub fn trait_impl_ident(trait_name: &str) -> Ident { - Ident::new( - &format!("UniFFICallbackHandler{trait_name}"), - Span::call_site(), - ) + ::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( @@ -131,11 +63,11 @@ pub fn ffi_converter_callback_interface_impl( trait_impl_ident: &Ident, udl_mode: bool, ) -> TokenStream { - let trait_name = ident_to_string(trait_ident); + 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 derive_ffi_traits = derive_ffi_traits(&box_dyn_trait, udl_mode, &["LiftRef", "LiftReturn"]); + 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(), @@ -161,85 +93,66 @@ pub fn ffi_converter_callback_interface_impl( ::uniffi::metadata::codes::TYPE_CALLBACK_INTERFACE, ) .concat_str(#mod_path) - .concat_str(#trait_name); + .concat_str(#name); } - #derive_ffi_traits + unsafe #lift_ref_impl_spec { + type LiftType = #box_dyn_trait; + } } } -/// 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 { +fn gen_method_impl(sig: &FnSignature, internals_ident: &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 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 { - Some(ReceiverArg::Ref) => quote! { &self }, - Some(ReceiverArg::Arc) => quote! { self: Arc }, None => { return Err(syn::Error::new( - *span, + 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 lower_exprs = sig.args.iter().map(|a| { - let lower_impl = a.lower_impl(); - let ident = &a.ident; - quote! { #lower_impl::lower(#ident) } - }); + let buf_ident = Ident::new("uniffi_args_buf", Span::call_site()); + let write_exprs = sig.write_exprs(&buf_ident); - let lift_return = sig.lift_return_impl(); + 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); - 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 - } - }) - } + #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, - docstring: String, ) -> syn::Result> { let trait_name = ident_to_string(self_ident); let callback_interface_items = create_metadata_items( @@ -249,14 +162,13 @@ pub(super) fn metadata_items( ::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(), + 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 da3c9455c888d..98c7d0ebe262c 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 fa7b61decabfc..f120ccc880bc2 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 83587ae386c3e..0000000000000 --- 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 9007ae2c56baf..3db09ea2b7d38 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 9c591252077da..69b6529d1e05b 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 929400c885f11..4cffddfa0eaca 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 6bcc07a14e07b..573a1eaadd7cb 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 41f5d016acebd..abf2743ec69fb 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 c82e9389bb614..afdb119cc41bf 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 97faad9c4dd23..9f213ea1d7fe9 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 index 31b45ce807240..cb02cde83fbf8 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 04d817001174f..34999eee18eae 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 64ac3486a3bfe..0000000000000 --- 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 5c931a09e368a..44a5bc3e63771 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 a41776bf8a984..f0be2e5a9871f 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 90f7b2d3cdcf6..e486d84d8963f 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, @@ -421,6 +387,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, @@ -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 9cfb77a244a4c..6e490a48663cc 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 6fec6cb3a3596..bf6525f2b5086 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 51bf156b50b11..24f8a6f2a872b 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 47b58d8bcfaca..0af9b557d8d30 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 5dacf0cf31729..a4f6f0bf54525 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 index 88ed1cb4b78e0..233a1e7795d29 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 fd03f3434af8f..346cd71c27918 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 64ac3486a3bfe..0000000000000 --- 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 7bb05808c4846..f06b4f29c1929 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 de5489f5f9a4b..6a91ab4a93272 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 dda3c3a3ce68c..3e15bb8e02c25 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 1615a1a7ca89a..a3e68fd23ebf4 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 ef9bdd954069d..58e6a9c8a09fa 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 195d9cc0b7b45..7a2d22ac42e15 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 259557ad07e4f..0c4c187dc010c 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 a9dad5d6c562b..5e6e72a7f77da 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 5fbf022644590..78f254425491c 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 ea98cd7a99896..14a7a4c6f1bf0 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 25f2af17bf215..98fa4d6a227ba 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 8306a25dd2a5d..c3f9b170df4ec 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 index 13a9d357d5292..9eb63aa3c1649 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 66703cf607338..072d3f9a2a654 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 88e4cec017264..889dc0da193cf 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 d36f6e5438b06..fadf89ba8b7c7 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 b775d526dca16..3c9b23cac5560 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 ab3c10d3c3cca..5e30909c3894d 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 71ab7c33b5bad..610a34fa143d3 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 60673cdcec31b..ed28573218dc0 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 4be3ca43e8917..336e4784e103a 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 ba563f514a3a8..98b8d8a95b2b0 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 af507f499f05e..dc688dc41efab 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 46062736f2639..3c8c2c71e1cc6 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 6c5772ae7f3a6..f430cd73840d0 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 5ef165dc73a53..32232c64b97d5 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 2a4663e1cbef9..653164ea50fbb 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), ) } 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 e839b6f17d485..0f12f8e783e76 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), ) 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 7ab2e2d8e2b92..eb841e308748b 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), ) @@ -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), ) @@ -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 4d34a46d9e8c0..be4d346733c37 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), ) } @@ -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), ) diff --git a/toolkit/components/uniffi-bindgen-gecko-js/config.toml b/toolkit/components/uniffi-bindgen-gecko-js/config.toml index d8404f51428e5..7b7943dfbdcfb 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/config.toml +++ b/toolkit/components/uniffi-bindgen-gecko-js/config.toml @@ -72,27 +72,16 @@ crate_name = "uniffi_todolist" udl_file = "third_party/rust/uniffi-example-todolist/src/todolist.udl" fixture = true -[fixture_refcounts] -crate_name = "uniffi_fixture_refcounts" -udl_file = "toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl" +[fixture_callbacks] +crate_name = "uniffi_fixture_callbacks" +udl_file = "toolkit/components/uniffi-fixture-callbacks/src/callbacks.udl" fixture = true -[fixture_refcounts.receiver_thread] -default = "main" - -# 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.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 62766a45a4ae0..e60f95decea1a 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 581478cc8a318..107da01016c7f 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 88c9390225321..6c6f9f9bb7039 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 6ff9a25fa9279..830775dbf9825 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( - 58, // 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( - 59, // 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/RustRefcounts.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRefcounts.sys.mjs deleted file mode 100644 index d8a598d15021a..0000000000000 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRefcounts.sys.mjs +++ /dev/null @@ -1,388 +0,0 @@ -// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate. -// Trust me, you don't want to mess with it! - -import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs"; - - - -// Objects intended to be used in the unit tests -export var UnitTestObjs = {}; - -// Write/Read data to/from an ArrayBuffer -class ArrayBufferDataStream { - constructor(arrayBuffer) { - this.dataView = new DataView(arrayBuffer); - this.pos = 0; - } - - readUint8() { - let rv = this.dataView.getUint8(this.pos); - this.pos += 1; - return rv; - } - - writeUint8(value) { - this.dataView.setUint8(this.pos, value); - this.pos += 1; - } - - readUint16() { - let rv = this.dataView.getUint16(this.pos); - this.pos += 2; - return rv; - } - - writeUint16(value) { - this.dataView.setUint16(this.pos, value); - this.pos += 2; - } - - readUint32() { - let rv = this.dataView.getUint32(this.pos); - this.pos += 4; - return rv; - } - - writeUint32(value) { - this.dataView.setUint32(this.pos, value); - this.pos += 4; - } - - readUint64() { - let rv = this.dataView.getBigUint64(this.pos); - this.pos += 8; - return Number(rv); - } - - writeUint64(value) { - this.dataView.setBigUint64(this.pos, BigInt(value)); - this.pos += 8; - } - - - readInt8() { - let rv = this.dataView.getInt8(this.pos); - this.pos += 1; - return rv; - } - - writeInt8(value) { - this.dataView.setInt8(this.pos, value); - this.pos += 1; - } - - readInt16() { - let rv = this.dataView.getInt16(this.pos); - this.pos += 2; - return rv; - } - - writeInt16(value) { - this.dataView.setInt16(this.pos, value); - this.pos += 2; - } - - readInt32() { - let rv = this.dataView.getInt32(this.pos); - this.pos += 4; - return rv; - } - - writeInt32(value) { - this.dataView.setInt32(this.pos, value); - this.pos += 4; - } - - readInt64() { - let rv = this.dataView.getBigInt64(this.pos); - this.pos += 8; - return Number(rv); - } - - writeInt64(value) { - this.dataView.setBigInt64(this.pos, BigInt(value)); - this.pos += 8; - } - - readFloat32() { - let rv = this.dataView.getFloat32(this.pos); - this.pos += 4; - return rv; - } - - writeFloat32(value) { - this.dataView.setFloat32(this.pos, value); - this.pos += 4; - } - - readFloat64() { - let rv = this.dataView.getFloat64(this.pos); - this.pos += 8; - return rv; - } - - writeFloat64(value) { - this.dataView.setFloat64(this.pos, value); - this.pos += 8; - } - - - writeString(value) { - const encoder = new TextEncoder(); - // Note: in order to efficiently write this data, we first write the - // string data, reserving 4 bytes for the size. - const dest = new Uint8Array(this.dataView.buffer, this.pos + 4); - const encodeResult = encoder.encodeInto(value, dest); - if (encodeResult.read != value.length) { - throw new UniFFIError( - "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?" - ); - } - const size = encodeResult.written; - // Next, go back and write the size before the string data - this.dataView.setUint32(this.pos, size); - // Finally, advance our position past both the size and string data - this.pos += size + 4; - } - - readString() { - const decoder = new TextDecoder(); - const size = this.readUint32(); - const source = new Uint8Array(this.dataView.buffer, this.pos, size) - const value = decoder.decode(source); - this.pos += size; - return value; - } - - // Reads a SingletonObject pointer from the data stream - // UniFFI Pointers are **always** 8 bytes long. That is enforced - // by the C++ and Rust Scaffolding code. - readPointerSingletonObject() { - const pointerId = 6; // refcounts:SingletonObject - const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); - this.pos += 8; - return res; - } - - // Writes a SingletonObject pointer into the data stream - // UniFFI Pointers are **always** 8 bytes long. That is enforced - // by the C++ and Rust Scaffolding code. - writePointerSingletonObject(value) { - const pointerId = 6; // refcounts:SingletonObject - UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); - this.pos += 8; - } - -} - -function handleRustResult(result, liftCallback, liftErrCallback) { - switch (result.code) { - case "success": - return liftCallback(result.data); - - case "error": - throw liftErrCallback(result.data); - - case "internal-error": - let message = result.internalErrorMessage; - if (message) { - throw new UniFFIInternalError(message); - } else { - throw new UniFFIInternalError("Unknown error"); - } - - default: - throw new UniFFIError(`Unexpected status code: ${result.code}`); - } -} - -class UniFFIError { - constructor(message) { - this.message = message; - } - - toString() { - return `UniFFIError: ${this.message}` - } -} - -class UniFFIInternalError extends UniFFIError {} - -// Base class for FFI converters -class FfiConverter { - // throw `UniFFITypeError` if a value to be converted has an invalid type - static checkType(value) { - if (value === undefined ) { - throw new UniFFITypeError(`undefined`); - } - if (value === null ) { - throw new UniFFITypeError(`null`); - } - } -} - -// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer -class FfiConverterArrayBuffer extends FfiConverter { - static lift(buf) { - return this.read(new ArrayBufferDataStream(buf)); - } - - static lower(value) { - const buf = new ArrayBuffer(this.computeSize(value)); - const dataStream = new ArrayBufferDataStream(buf); - this.write(dataStream, value); - return buf; - } -} - -// Symbols that are used to ensure that Object constructors -// can only be used with a proper UniFFI pointer -const uniffiObjectPtr = Symbol("uniffiObjectPtr"); -const constructUniffiObject = Symbol("constructUniffiObject"); -UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr; - -// Export the FFIConverter object to make external types work. -export class FfiConverterI32 extends FfiConverter { - static checkType(value) { - super.checkType(value); - if (!Number.isInteger(value)) { - throw new UniFFITypeError(`${value} is not an integer`); - } - if (value < -2147483648 || value > 2147483647) { - throw new UniFFITypeError(`${value} exceeds the I32 bounds`); - } - } - static computeSize() { - return 4; - } - static lift(value) { - return value; - } - static lower(value) { - return value; - } - static write(dataStream, value) { - dataStream.writeInt32(value) - } - static read(dataStream) { - return dataStream.readInt32() - } -} - -// Export the FFIConverter object to make external types work. -export class FfiConverterString extends FfiConverter { - static checkType(value) { - super.checkType(value); - if (typeof value !== "string") { - throw new UniFFITypeError(`${value} is not a string`); - } - } - - static lift(buf) { - const decoder = new TextDecoder(); - const utf8Arr = new Uint8Array(buf); - return decoder.decode(utf8Arr); - } - static lower(value) { - const encoder = new TextEncoder(); - return encoder.encode(value).buffer; - } - - static write(dataStream, value) { - dataStream.writeString(value); - } - - static read(dataStream) { - return dataStream.readString(); - } - - static computeSize(value) { - const encoder = new TextEncoder(); - return 4 + encoder.encode(value).length - } -} - -export class SingletonObject { - // Use `init` to instantiate this class. - // DO NOT USE THIS CONSTRUCTOR DIRECTLY - constructor(opts) { - if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) { - throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" + - "Please use a UDL defined constructor, or the init function for the primary constructor") - } - if (!opts[constructUniffiObject] instanceof UniFFIPointer) { - throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer") - } - this[uniffiObjectPtr] = opts[constructUniffiObject]; - } - - method() { - const liftResult = (result) => undefined; - const liftError = null; - const functionCall = () => { - return UniFFIScaffolding.callSync( - 55, // refcounts:uniffi_uniffi_fixture_refcounts_fn_method_singletonobject_method - FfiConverterTypeSingletonObject.lower(this), - ) - } - return handleRustResult(functionCall(), liftResult, liftError); - } - -} - -// Export the FFIConverter object to make external types work. -export class FfiConverterTypeSingletonObject extends FfiConverter { - static lift(value) { - const opts = {}; - opts[constructUniffiObject] = value; - return new SingletonObject(opts); - } - - static lower(value) { - const ptr = value[uniffiObjectPtr]; - if (!(ptr instanceof UniFFIPointer)) { - throw new UniFFITypeError("Object is not a 'SingletonObject' instance"); - } - return ptr; - } - - static read(dataStream) { - return this.lift(dataStream.readPointerSingletonObject()); - } - - static write(dataStream, value) { - dataStream.writePointerSingletonObject(value[uniffiObjectPtr]); - } - - static computeSize(value) { - return 8; - } -} - - - - - -export function getJsRefcount() { - - const liftResult = (result) => FfiConverterI32.lift(result); - const liftError = null; - const functionCall = () => { - return UniFFIScaffolding.callSync( - 56, // refcounts:uniffi_uniffi_fixture_refcounts_fn_func_get_js_refcount - ) - } - return handleRustResult(functionCall(), liftResult, liftError); -} - -export function getSingleton() { - - const liftResult = (result) => FfiConverterTypeSingletonObject.lift(result); - const liftError = null; - const functionCall = () => { - return UniFFIScaffolding.callSync( - 57, // refcounts:uniffi_uniffi_fixture_refcounts_fn_func_get_singleton - ) - } - return handleRustResult(functionCall(), liftResult, liftError); -} 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 f6db36163e64c..2d55aa787217d 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 @@ -158,7 +158,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. readPointerOptionneur() { - const pointerId = 7; // rondpoint:Optionneur + const pointerId = 6; // rondpoint:Optionneur const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); this.pos += 8; return res; @@ -168,7 +168,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. writePointerOptionneur(value) { - const pointerId = 7; // rondpoint:Optionneur + const pointerId = 6; // rondpoint:Optionneur UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); this.pos += 8; } @@ -178,7 +178,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. readPointerRetourneur() { - const pointerId = 8; // rondpoint:Retourneur + const pointerId = 7; // rondpoint:Retourneur const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); this.pos += 8; return res; @@ -188,7 +188,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. writePointerRetourneur(value) { - const pointerId = 8; // rondpoint:Retourneur + const pointerId = 7; // rondpoint:Retourneur UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); this.pos += 8; } @@ -198,7 +198,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. readPointerStringifier() { - const pointerId = 9; // rondpoint:Stringifier + const pointerId = 8; // rondpoint:Stringifier const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); this.pos += 8; return res; @@ -208,7 +208,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. writePointerStringifier(value) { - const pointerId = 9; // rondpoint:Stringifier + const pointerId = 8; // rondpoint:Stringifier UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); this.pos += 8; } @@ -620,7 +620,7 @@ export class Optionneur { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 61, // 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( - 62, // 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( - 63, // 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( - 64, // 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( - 65, // 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( - 66, // 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( - 67, // 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( - 68, // 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( - 69, // 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( - 70, // 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( - 71, // 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( - 72, // 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( - 73, // 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( - 74, // 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( - 75, // 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( - 76, // 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( - 77, // 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( - 78, // 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( - 79, // 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( - 80, // 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( - 81, // 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( - 82, // 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( - 83, // 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( - 84, // 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( - 85, // 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( - 86, // 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), ) @@ -1309,7 +1309,7 @@ export class Retourneur { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 88, // 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( - 89, // 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( - 90, // 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( - 91, // 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( - 92, // 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( - 93, // 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( - 94, // 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( - 95, // 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( - 96, // 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( - 97, // 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( - 98, // 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( - 99, // 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( - 100, // 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( - 101, // 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( - 102, // 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( - 103, // 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), ) @@ -1748,7 +1748,7 @@ export class Stringifier { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 105, // 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( - 106, // 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( - 107, // 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( - 108, // 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( - 109, // 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( - 110, // 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( - 111, // 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( - 112, // 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( - 113, // 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( - 114, // 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( - 115, // 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( - 116, // 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( - 117, // 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), ) @@ -3284,7 +3284,7 @@ export function copieCarte(c) { throw e; } return UniFFIScaffolding.callAsync( - 118, // 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( - 119, // 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( - 120, // 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( - 121, // 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( - 122, // 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 c25a488009074..2a045bdbcad11 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 @@ -158,7 +158,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. readPointerSprite() { - const pointerId = 10; // sprites:Sprite + const pointerId = 9; // sprites:Sprite const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); this.pos += 8; return res; @@ -168,7 +168,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. writePointerSprite(value) { - const pointerId = 10; // sprites:Sprite + const pointerId = 9; // sprites:Sprite UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); this.pos += 8; } @@ -325,7 +325,7 @@ export class Sprite { throw e; } return UniFFIScaffolding.callAsync( - 124, // 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( - 125, // 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( - 126, // 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( - 127, // 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( - 128, // 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), ) @@ -678,7 +678,7 @@ export function translate(position,direction) { throw e; } return UniFFIScaffolding.callAsync( - 129, // 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 ddeccc9bf29fd..9c6f360194543 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 @@ -158,7 +158,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. readPointerTodoList() { - const pointerId = 11; // todolist:TodoList + const pointerId = 10; // todolist:TodoList const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); this.pos += 8; return res; @@ -168,7 +168,7 @@ class ArrayBufferDataStream { // UniFFI Pointers are **always** 8 bytes long. That is enforced // by the C++ and Rust Scaffolding code. writePointerTodoList(value) { - const pointerId = 11; // todolist:TodoList + const pointerId = 10; // todolist:TodoList UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); this.pos += 8; } @@ -298,7 +298,7 @@ export class TodoList { const liftError = null; const functionCall = () => { return UniFFIScaffolding.callAsync( - 131, // 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( - 132, // 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( - 133, // 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( - 134, // 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( - 135, // 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( - 136, // 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( - 137, // 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( - 138, // 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( - 139, // 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( - 140, // 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( - 141, // 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( - 142, // todolist:uniffi_uniffi_todolist_fn_method_todolist_make_default + 127, // todolist:uniffi_uniffi_todolist_fn_method_todolist_make_default FfiConverterTypeTodoList.lower(this), ) } @@ -880,7 +880,7 @@ export function createEntryWith(todo) { throw e; } return UniFFIScaffolding.callAsync( - 143, // 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( - 144, // 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( - 145, // 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/moz.build b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build index eed04220cb56b..d5ff2d7cb6c66 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build @@ -12,7 +12,6 @@ components = [ "ExternalTypes", "FixtureCallbacks", "Geometry", - "Refcounts", "Rondpoint", "Sprites", "Todolist", diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_refcounts.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_refcounts.js deleted file mode 100644 index 790d981104cef..0000000000000 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_refcounts.js +++ /dev/null @@ -1,57 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -const { getSingleton, getJsRefcount } = ChromeUtils.importESModule( - "resource://gre/modules/RustRefcounts.sys.mjs" -); - -// Test refcounts when we call methods. -// -// Each method call requires that we clone the Arc pointer on the JS side, then pass it to Rust -// which will consumer the reference. Make sure we get this right - -function createObjectAndCallMethods() { - const obj = getSingleton(); - obj.method(); -} - -add_test(() => { - // Create an object that we'll keep around. If the ref count ends up being low, we don't want - // to reduce it below 0, since the Rust code may catch that and clamp it - const obj = getSingleton(); - createObjectAndCallMethods(); - Cu.forceGC(); - Cu.forceCC(); - do_test_pending(); - do_timeout(500, () => { - Assert.equal(getJsRefcount(), 1); - // Use `obj` to avoid unused warnings and try to ensure that JS doesn't destroy it early - obj.method(); - do_test_finished(); - run_next_test(); - }); -}); - -// Test refcounts when creating/destroying objects -function createAndDeleteObjects() { - [getSingleton(), getSingleton(), getSingleton()]; -} - -add_test(() => { - const obj = getSingleton(); - createAndDeleteObjects(); - Cu.forceGC(); - Cu.forceCC(); - do_timeout(500, () => { - Assert.equal(getJsRefcount(), 1); - obj.method(); - do_test_finished(); - run_next_test(); - }); -}); - -// As we implement more UniFFI features we should probably add refcount tests for it. -// Some features that should probably have tests: -// - Async methods -// - UniFFI builtin trait methods like 'to_string' -// - Rust trait objects 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 801e95382f7b8..76814ff1991d8 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,33 +2,18 @@ ["test_arithmetic.js"] -# I think this can be re-enabled when we implement https://bugzilla.mozilla.org/show_bug.cgi?id=1888668 -lineno = "3" - ["test_callbacks.js"] -disabled = "Temporarily disabled until we can re-enable callback support" -lineno = "8" ["test_custom_types.js"] -lineno = "12" ["test_external_types.js"] -lineno = "15" ["test_geometry.js"] -lineno = "18" - -["test_refcounts.js"] -lineno = "21" ["test_rondpoint.js"] -lineno = "24" ["test_sprites.js"] -lineno = "27" ["test_todolist.js"] -lineno = "30" ["test_type_checking.js"] -lineno = "33" 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 7b63e8f3af7ad..685c3c2bf3700 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 cd9af529a7c49..efd7b42456281 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 83aeae8086503..5c4ed8c2f56f1 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-fixture-external-types/Cargo.toml b/toolkit/components/uniffi-fixture-external-types/Cargo.toml index 46ee01662d225..f9ac840c3fa31 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-fixture-refcounts/Cargo.toml b/toolkit/components/uniffi-fixture-refcounts/Cargo.toml deleted file mode 100644 index 877e5027112e9..0000000000000 --- a/toolkit/components/uniffi-fixture-refcounts/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "uniffi-fixture-refcounts" -edition = "2021" -version = "0.21.0" -license = "MPL-2.0" -publish = false - -[dependencies] -uniffi = { workspace = true } - -[build-dependencies] -uniffi = { workspace = true, features = ["build"] } diff --git a/toolkit/components/uniffi-fixture-refcounts/build.rs b/toolkit/components/uniffi-fixture-refcounts/build.rs deleted file mode 100644 index 9ea03e12de133..0000000000000 --- a/toolkit/components/uniffi-fixture-refcounts/build.rs +++ /dev/null @@ -1,7 +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/. */ - -fn main() { - uniffi::generate_scaffolding("./src/refcounts.udl").unwrap(); -} diff --git a/toolkit/components/uniffi-fixture-refcounts/src/lib.rs b/toolkit/components/uniffi-fixture-refcounts/src/lib.rs deleted file mode 100644 index e453b22a4ad3b..0000000000000 --- a/toolkit/components/uniffi-fixture-refcounts/src/lib.rs +++ /dev/null @@ -1,28 +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 crate exists to test managing the Rust Arc strong counts as JS objects are -/// created/destroyed. See `test_refcounts.js` for how it's used. - -use std::sync::{Arc, Mutex}; - -pub struct SingletonObject; - -impl SingletonObject { - pub fn method(&self) { } -} - -static SINGLETON: Mutex>> = Mutex::new(None); - -pub fn get_singleton() -> Arc { - Arc::clone(SINGLETON.lock().unwrap().get_or_insert_with(|| Arc::new(SingletonObject))) -} - -pub fn get_js_refcount() -> i32 { - // Subtract 2: one for the reference in the Mutex and one for the temporary reference that - // we're calling Arc::strong_count on. - (Arc::strong_count(&get_singleton()) as i32) - 2 -} - -include!(concat!(env!("OUT_DIR"), "/refcounts.uniffi.rs")); diff --git a/toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl b/toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl deleted file mode 100644 index 25ec83cfcc5dd..0000000000000 --- a/toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl +++ /dev/null @@ -1,8 +0,0 @@ -namespace refcounts { - SingletonObject get_singleton(); - i32 get_js_refcount(); -}; - -interface SingletonObject { - void method(); -}; diff --git a/toolkit/components/uniffi-js/OwnedRustBuffer.cpp b/toolkit/components/uniffi-js/OwnedRustBuffer.cpp index f14033a213923..4e334a966e757 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/ScaffoldingConverter.h b/toolkit/components/uniffi-js/ScaffoldingConverter.h index d11fd0c31458a..ae5629e2e4f30 100644 --- a/toolkit/components/uniffi-js/ScaffoldingConverter.h +++ b/toolkit/components/uniffi-js/ScaffoldingConverter.h @@ -173,7 +173,7 @@ class ScaffoldingObjectConverter { if (!value.IsSamePtrType(PointerType)) { return Err("Bad pointer type"_ns); } - return value.ClonePtr(); + return value.GetPtr(); } static void* IntoRust(void* aValue) { return aValue; } diff --git a/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp b/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp index d8c4d0d8a0a46..739569db01c12 100644 --- a/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp +++ b/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp @@ -31,14 +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_refcounts_fn_clone_singletonobject(void *, RustCallStatus*); - void uniffi_uniffi_fixture_refcounts_fn_free_singletonobject(void *, RustCallStatus*); - void uniffi_uniffi_fixture_refcounts_fn_method_singletonobject_method(void *, RustCallStatus*); - int32_t uniffi_uniffi_fixture_refcounts_fn_func_get_js_refcount(RustCallStatus*); - void * uniffi_uniffi_fixture_refcounts_fn_func_get_singleton(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*); @@ -66,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*); @@ -84,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*); @@ -104,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*); @@ -112,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*); @@ -132,42 +125,51 @@ extern "C" { } // Define pointer types -const static mozilla::uniffi::UniFFIPointerType kRefcountsSingletonObjectPointerType { - "refcounts::SingletonObject"_ns, - uniffi_uniffi_fixture_refcounts_fn_clone_singletonobject, - uniffi_uniffi_fixture_refcounts_fn_free_singletonobject, -}; 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(); @@ -176,399 +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: { // refcounts:uniffi_uniffi_fixture_refcounts_fn_clone_singletonobject - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRefcountsSingletonObjectPointerType>>; - return Some(CallHandler::CallAsync(uniffi_uniffi_fixture_refcounts_fn_clone_singletonobject, aGlobal, aArgs, "uniffi_uniffi_fixture_refcounts_fn_clone_singletonobject: "_ns, aError)); - } - case 55: { // refcounts:uniffi_uniffi_fixture_refcounts_fn_method_singletonobject_method - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRefcountsSingletonObjectPointerType>>; - return Some(CallHandler::CallAsync(uniffi_uniffi_fixture_refcounts_fn_method_singletonobject_method, aGlobal, aArgs, "uniffi_uniffi_fixture_refcounts_fn_method_singletonobject_method: "_ns, aError)); - } - case 56: { // refcounts:uniffi_uniffi_fixture_refcounts_fn_func_get_js_refcount - using CallHandler = ScaffoldingCallHandler>; - return Some(CallHandler::CallAsync(uniffi_uniffi_fixture_refcounts_fn_func_get_js_refcount, aGlobal, aArgs, "uniffi_uniffi_fixture_refcounts_fn_func_get_js_refcount: "_ns, aError)); + 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 57: { // refcounts:uniffi_uniffi_fixture_refcounts_fn_func_get_singleton - using CallHandler = ScaffoldingCallHandler>; - return Some(CallHandler::CallAsync(uniffi_uniffi_fixture_refcounts_fn_func_get_singleton, aGlobal, aArgs, "uniffi_uniffi_fixture_refcounts_fn_func_get_singleton: "_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 58: { // geometry:uniffi_uniffi_geometry_fn_func_gradient + 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 59: { // 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 60: { // 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 61: { // 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 62: { // 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 63: { // 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 64: { // 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 65: { // 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 66: { // 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 67: { // 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 68: { // 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 69: { // 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 70: { // 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 71: { // 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 72: { // 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 73: { // 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 74: { // 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 75: { // 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 76: { // 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 77: { // 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 78: { // 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 79: { // 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 80: { // 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 81: { // 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 82: { // 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 83: { // 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 84: { // 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 85: { // 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 86: { // 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 87: { // 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 88: { // 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 89: { // 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 90: { // 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 91: { // 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 92: { // 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 93: { // 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 94: { // 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 95: { // 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 96: { // 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 97: { // 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 98: { // 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 99: { // 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 100: { // 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 101: { // 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 102: { // 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 103: { // 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 104: { // 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 105: { // 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 106: { // 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 107: { // 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 108: { // 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 109: { // 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 110: { // 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 111: { // 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 112: { // 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 113: { // 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 114: { // 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 115: { // 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 116: { // 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 117: { // 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 118: { // 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 119: { // 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 120: { // 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 121: { // 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 122: { // 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 123: { // 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 124: { // 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 125: { // 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 126: { // 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 127: { // 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 128: { // 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 129: { // 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 130: { // 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 131: { // 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 132: { // 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 133: { // 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 134: { // 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 135: { // 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 136: { // 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 137: { // 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 138: { // 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 139: { // 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 140: { // 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 141: { // 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 142: { // 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 143: { // 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 144: { // 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 145: { // 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)); } @@ -578,497 +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: { // refcounts:uniffi_uniffi_fixture_refcounts_fn_clone_singletonobject - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRefcountsSingletonObjectPointerType>>; - CallHandler::CallSync(uniffi_uniffi_fixture_refcounts_fn_clone_singletonobject, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_fixture_refcounts_fn_clone_singletonobject: "_ns, aError); - return true; - } - case 55: { // refcounts:uniffi_uniffi_fixture_refcounts_fn_method_singletonobject_method - using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRefcountsSingletonObjectPointerType>>; - CallHandler::CallSync(uniffi_uniffi_fixture_refcounts_fn_method_singletonobject_method, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_fixture_refcounts_fn_method_singletonobject_method: "_ns, aError); + 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 56: { // refcounts:uniffi_uniffi_fixture_refcounts_fn_func_get_js_refcount - using CallHandler = ScaffoldingCallHandler>; - CallHandler::CallSync(uniffi_uniffi_fixture_refcounts_fn_func_get_js_refcount, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_fixture_refcounts_fn_func_get_js_refcount: "_ns, aError); + 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 57: { // refcounts:uniffi_uniffi_fixture_refcounts_fn_func_get_singleton - using CallHandler = ScaffoldingCallHandler>; - CallHandler::CallSync(uniffi_uniffi_fixture_refcounts_fn_func_get_singleton, aGlobal, aArgs, aReturnValue, "uniffi_uniffi_fixture_refcounts_fn_func_get_singleton: "_ns, aError); - return true; - } - case 58: { // geometry:uniffi_uniffi_geometry_fn_func_gradient + 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 59: { // 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 60: { // 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 61: { // 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 62: { // 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 63: { // 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 64: { // 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 65: { // 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 66: { // 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 67: { // 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 68: { // 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 69: { // 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 70: { // 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 71: { // 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 72: { // 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 73: { // 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 74: { // 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 75: { // 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 76: { // 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 77: { // 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 78: { // 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 79: { // 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 80: { // 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 81: { // 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 82: { // 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 83: { // 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 84: { // 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 85: { // 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 86: { // 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 87: { // 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 88: { // 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 89: { // 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 90: { // 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 91: { // 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 92: { // 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 93: { // 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 94: { // 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 95: { // 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 96: { // 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 97: { // 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 98: { // 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 99: { // 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 100: { // 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 101: { // 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 102: { // 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 103: { // 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 104: { // 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 105: { // 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 106: { // 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 107: { // 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 108: { // 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 109: { // 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 110: { // 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 111: { // 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 112: { // 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 113: { // 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 114: { // 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 115: { // 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 116: { // 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 117: { // 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 118: { // 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 119: { // 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 120: { // 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 121: { // 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 122: { // 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 123: { // 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 124: { // 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 125: { // 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 126: { // 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 127: { // 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 128: { // 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 129: { // 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 130: { // 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 131: { // 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 132: { // 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 133: { // 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 134: { // 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 135: { // 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 136: { // 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 137: { // 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 138: { // 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 139: { // 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 140: { // 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 141: { // 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 142: { // 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 143: { // 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 144: { // 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 145: { // 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; @@ -1080,27 +1019,23 @@ bool UniFFIFixturesCallSync(const GlobalObject& aGlobal, uint64_t aId, const Seq Maybe> UniFFIFixturesReadPointer(const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { const UniFFIPointerType* type; switch (aId) { - case 6: { // refcounts:SingletonObject - type = &kRefcountsSingletonObjectPointerType; - break; - } - case 7: { // rondpoint:Optionneur + case 6: { // rondpoint:Optionneur type = &kRondpointOptionneurPointerType; break; } - case 8: { // rondpoint:Retourneur + case 7: { // rondpoint:Retourneur type = &kRondpointRetourneurPointerType; break; } - case 9: { // rondpoint:Stringifier + case 8: { // rondpoint:Stringifier type = &kRondpointStringifierPointerType; break; } - case 10: { // sprites:Sprite + case 9: { // sprites:Sprite type = &kSpritesSpritePointerType; break; } - case 11: { // todolist:TodoList + case 10: { // todolist:TodoList type = &kTodolistTodoListPointerType; break; } @@ -1113,27 +1048,23 @@ Maybe> UniFFIFixturesReadPointer(const GlobalObj bool UniFFIFixturesWritePointer(const GlobalObject& aGlobal, uint64_t aId, const UniFFIPointer& aPtr, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { const UniFFIPointerType* type; switch (aId) { - case 6: { // refcounts:SingletonObject - type = &kRefcountsSingletonObjectPointerType; - break; - } - case 7: { // rondpoint:Optionneur + case 6: { // rondpoint:Optionneur type = &kRondpointOptionneurPointerType; break; } - case 8: { // rondpoint:Retourneur + case 7: { // rondpoint:Retourneur type = &kRondpointRetourneurPointerType; break; } - case 9: { // rondpoint:Stringifier + case 8: { // rondpoint:Stringifier type = &kRondpointStringifierPointerType; break; } - case 10: { // sprites:Sprite + case 9: { // sprites:Sprite type = &kSpritesSpritePointerType; break; } - case 11: { // todolist:TodoList + case 10: { // todolist:TodoList type = &kTodolistTodoListPointerType; break; } diff --git a/toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp b/toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp index 20a581d5e2c2e..c4881ac79d52b 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 b77ef853957a7..c3a1eba93dc05 100644 --- a/toolkit/components/uniffi-js/UniFFIPointer.cpp +++ b/toolkit/components/uniffi-js/UniFFIPointer.cpp @@ -82,7 +82,7 @@ void UniFFIPointer::Write(const ArrayBuffer& aArrayBuff, uint32_t aPosition, // a pointer we do the reverse here const auto& data_ptr = aData.Subspan(aPosition, 8); mozilla::BigEndian::writeUint64(data_ptr.Elements(), - (uint64_t)ClonePtr()); + (uint64_t)GetPtr()); return true; })) { aError.ThrowRangeError("position is out of range"); @@ -100,14 +100,10 @@ JSObject* UniFFIPointer::WrapObject(JSContext* aCx, return dom::UniFFIPointer_Binding::Wrap(aCx, this, aGivenProto); } -void* UniFFIPointer::ClonePtr() const { +void* UniFFIPointer::GetPtr() const { MOZ_LOG(sUniFFIPointerLogger, LogLevel::Info, - ("[UniFFI] Cloning raw 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 cloned; + ("[UniFFI] Getting raw pointer")); + return this->mPtr; } bool UniFFIPointer::IsSamePtrType(const UniFFIPointerType* aType) const { diff --git a/toolkit/components/uniffi-js/UniFFIPointer.h b/toolkit/components/uniffi-js/UniFFIPointer.h index f9a95c309ea1b..59acc0ca666c8 100644 --- a/toolkit/components/uniffi-js/UniFFIPointer.h +++ b/toolkit/components/uniffi-js/UniFFIPointer.h @@ -36,13 +36,15 @@ class UniFFIPointer final : public nsISupports, public nsWrapperCache { nsISupports* GetParentObject() { return nullptr; } /** - * Clone the raw pointer that `UniFFIPointer` holds - * - * Use this when lowering the pointer to pass it across the FFI, for example: - * - When calling a method - * - When passing the object as an argument to a function + * returns the raw pointer `UniFFIPointer` holds + * This is safe because: + * - The pointer was allocated in Rust as a reference counted `Arc` + * - Rust cloned the pointer without destructing it when passed into C++ + * - Eventually, when the destructor of `UniFFIPointer` runs, we return + * ownership to Rust, which then decrements the count and deallocates the + * memory the pointer points to. */ - void* ClonePtr() const; + void* GetPtr() const; /** * Returns true if the pointer type `this` holds is the same as the argument diff --git a/toolkit/components/uniffi-js/UniFFIPointerType.h b/toolkit/components/uniffi-js/UniFFIPointerType.h index 25294cfc9de19..7236e50cb79cd 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 608b8063aeffa..2907af8f51a1a 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 16b674fdae8ac..a542f707a144c 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -72,19 +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 } -uniffi-fixture-refcounts = { path = "../../../components/uniffi-fixture-refcounts/", 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 @@ -146,7 +145,7 @@ thread_sanitizer = ["xpcom/thread_sanitizer"] uniffi_fixtures = [ "uniffi-example-arithmetic", "uniffi-example-geometry", "uniffi-example-rondpoint", "uniffi-example-sprites", "uniffi-example-todolist", "uniffi-example-custom-types", "uniffi-fixture-callbacks", - "uniffi-fixture-external-types", "uniffi-fixture-refcounts", + "uniffi-fixture-external-types", ] webmidi_midir_impl = ["midir_impl"] icu4x = ["jsrust_shared/icu4x"] diff --git a/toolkit/library/rust/shared/lib.rs b/toolkit/library/rust/shared/lib.rs index 7108e3c17c064..a6dfe60411f9b 100644 --- a/toolkit/library/rust/shared/lib.rs +++ b/toolkit/library/rust/shared/lib.rs @@ -136,7 +136,6 @@ mod uniffi_fixtures { uniffi_fixture_callbacks::uniffi_reexport_scaffolding!(); uniffi_custom_types::uniffi_reexport_scaffolding!(); uniffi_fixture_external_types::uniffi_reexport_scaffolding!(); - uniffi_fixture_refcounts::uniffi_reexport_scaffolding!(); uniffi_geometry::uniffi_reexport_scaffolding!(); uniffi_rondpoint::uniffi_reexport_scaffolding!(); uniffi_sprites::uniffi_reexport_scaffolding!(); @@ -175,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 a273626b588b3..611ab660f5058 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